Mybatis、配置、动态sql、一级,二级缓存

接口式编程
1、MyBatis可以使用简单的XML或注解用于配置和原
始映射,将接口和Java的POJO(Plain Old Java
Objects,普通的Java对象)映射成数据库中的记

​ jdbc: Dao ------------------> DaoImpl

​ Mybatis Mapper -------------> xxMapper.xml

​ 2、SqlSession代表和数据库的一次会话,用完须关闭
​ 3、SqlSession和Connection两者都不是线程安全的,每次使用都应该去获取新的对象
​ 4、Mapper接口没有实现类,但是mybatis会为它生成一个代理对象。(将接口与xml进行绑定)
​ EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMappper.getClass);
​ 5、两个重要的配置文件
​mybatis的全局配置文件:数据库连接池信息、事务管理器信息、系统运行环境信息等
sql映射文件:保存了每一个sql语句的映射信息

全局配置文件
MyBatis 的配置文件包含了影响 MyBatis 行为甚深的
设置(settings)和属性(properties)信息。文档的
顶层结构如下:
configuration 配置
properties 属性
settings 设置
typeAliases 类型命名
typeHandlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments 环境
-------environment 环境变量
-------------transactionManager 事务管理器
-------------dataSource 数据源
databaseIdProvider 数据库厂商标识
mappers 映射器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"></properties>
resource:引入类路径下的资源
url:引入网络路径下或者磁盘路径下的资源
<settings>
        <!-- 开启驼峰匹配:完成从经典的数据库列名(下划线)到驼峰式属性的映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 开启缓存 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- setting还有好几种属性 -->
</settings>

databaseIdProvider标签:支持多数据厂商的	type属性作用就是得到数据库厂商的标识(Mysql、Oracle、SQL server…)
<databaseIdProvider type="DB_VENDOR">
        <property name="Mysql" value="mysql"/>
        <property name="Oracle" value="oracle"/>
        <property name="SQL server" value="sqlserver"/>
</databaseIdProvider>

id:指定当前环境的唯一标识
transactionManager、和dataSource都必须有
<environments default="itg">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED" >
                <property name="driverClassName" value="${jdbc.driverClass}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
        <environment id="itg">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED" >
                <property name="driverClassName" value="${jdbcItg.driverClass}"></property>
                <property name="url" value="${jdbcItg.url}"></property>
                <property name="username" value="${jdbcItg.username}"></property>
                <property name="password" value="${jdbcItg.password}"></property>
            </dataSource>
        </environment>
    </environments>

mapper注入 别名扫描,最好是整合spring的时候在spring里面配置,
  <!-- 注入映射文件路径,mybatis/mapper/**/*.xml表示匹配mybatis/mapper目录及子目录下所有的xml文件 -->
        <property name="mapperLocations" value="classpath:mybatis/mapper/**/*.xml"></property>
        <!-- 别名扫描 -->
        <property name="typeAliasesPackage" value="com.kk.domain"></property>
    
</configuration>

sql映射文件
#和$的区别
#{key}:获取参数的值,预编译到SQL中。安全
${key}:获取参数的值,拼接到SQL中。有SQL注入问
题。应用:ORDER BY ${name},分表查询 select * from ${year}_name ;

cache –命名空间的二级缓存配置
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 自定义结果集映射
parameterMap – 已废弃!老式风格的参数映射
sql –抽取可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句

    开启自动生成主键
    <insert id="saveUser" useGeneratedKeys="true" keyProperty="id">
      INSERT INTO `kkkk`.`users` ( `age`, `name`, `birthday`, `salary`)
      VALUES ( #{age}, #{name}, '1991-02-28', '99999')
    </insert>


自定义resultMap,实现高级结果集映射

<resultMap type="User" id="MySimpleEmp">
        <!--指定主键列的封装规则
        id定义主键会底层有优化;
        column:指定哪一列
        property:指定对应的javaBean属性
          -->
        <id column="id" property="id"/>
        <!-- 定义普通列封装规则 -->
        <result column="name" property="name"/>
        <!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
        <result column="age" property="age"/>

        多对一的情况 多个人共有一个老师
        两种方式
        1:关联查询
        property="dept":指定哪个属性是联合的对象
	    javaType:指定这个属性对象的类型
        <association property="teacher" javaType="Teacher">
            <id column="Tid" property="id"/>
            <result column="teacherName" property="teacherName"/>
            <result column="teacherAge" property="teacherAge"/>
        </association>
        2:分步查询
        select:调用目标的方法查询当前属性的值
        column:将指定列的值传入目标方法
        <association property="teacher"
                     select="com.kk.mapper.UserMapper.+分布查询的id(saveUser)"
                     column="id">
        </association>

        一对多的情况  一个人有多个老师,也是两种写法
        1:
        ofType:集合中的类型
        columnPrefix:数据库中查询出来的column前缀
        <collection property="teacher" ofType="Teacher" columnPrefix="T_">
            <!-- 定义这个集合中元素的封装规则 -->
            <id column="id" property="id"/>
            <result column="teacherName" property="teacherName"/>
            <result column="teacherAge" property="teacherAge"/>
        </collection>
        2:分步查询
        <collection property="teacher" select="com.kk.mapper.UserMapper.+分布查询的id(saveUser)" column="id"> 
         有时候可传入的column不止一个,可以通过map的形式 column="{id=id,age=teacherAge}"
        </collection>

!!其实遇到这种情况,一般可以考虑是否开启懒加载,降低数据库的压力
<!--在mybatis的全局配置文件mybatis-config.xml中添加懒加载配置-->
	<settings>	
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>


discriminator鉴别器
假设只有年龄为11的时候去查老师,就可以用到这个
<resultMap type="User" id="MySimpleEmp">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <discriminator javaType="int" column="age">
            <case value="11" resultType="Teacher">
                <association property="teacher" select="namespace+id"column="id">
            </association>
        </case>
    </discriminator>

    </resultMap>


动态sql
mapper.xml中涉及到特殊字符,需要转义

在这里插入图片描述
不过如果sql中涉及很多特殊字符,可以使用<![CDATA[ 这里写sql]]>,放入这里面就不会进行转义;

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.kk.mapper.UserMapper">


    1: where +if
    <select id="getUser" resultType="User">
        select * from user
        <where>
            <!-- test:判断表达式(OGNL),从参数中取值进行判断,遇见特殊符号应该去写转义字符-->
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=&quot;&quot;">
                and last_name like #{lastName}
            </if>
        </where>
    </select>

    2:where+choose+when+otherwise,类似switch case
    <select id="getUser" resultType="User">
        select * from user
        <where>
            <!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个!! -->
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="email!=null">
                    email = #{email}
                </when>
                <otherwise>
                    gender = 0
                </otherwise>
            </choose>
        </where>
    </select>

    3:update+if
    <update id="updateEmp">
        update user
        <set>
            <if test="lastName!=null">
                last_name=#{lastName},
            </if>
            <if test="email!=null">
                email=#{email},
            </if>
        </set>
        where id=#{id}
    </update>

    4:批量保存 foreach
    <insert id="addUser">
        insert into user(
        <include refid="insertColumn"></include>
        )
        values
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>
    <!-- 这种方式需要数据库连接属性allowMultiQueries=true;
       如:jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
        这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
    <insert id="addUser">
        <foreach collection="emps" item="emp" separator=";">
            insert into tbl_employee(last_name,email,gender,d_id)
            values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>

    5:内置参数
    _databaseId:如果配置了databaseIdProvider标签。
    _databaseId就是代表当前数据库的别名
    <select id="getUser" resultType="User">
        <if test="_databaseId=='mysql'">
            select * from user where last_name like #{lastName}
        </if>
        <if test="_databaseId=='oracle'">
            select * from user where last_name like #{_parameter.lastName}
        </if>
    </select>

    6:抽取可重用的sql片段。方便后面引用
    <insert id="addUser">
        insert into user(
        <include refid="insertColumn"></include>  refid:这里引用下面的sql
        )
        values
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>

    <sql id="insertColumn">
        <if test="_databaseId=='oracle'">
            employee_id,last_name,email
        </if>
        <if test="_databaseId=='mysql'">
            last_name,email,gender,d_id
        </if>
    </sql>
</mapper>

Mybatis缓存
一级缓存和二级缓存。
1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存:
不能被关闭, 但可以调用 clearCache() 来清空本地缓存
• 同一次会话期间只要查询过的数据都会保存在当
前SqlSession的一个Map中 • key:hashCode+查询的SqlId+编写的sql查询语句+参数
一级缓存失效的四种情况
1、不同的SqlSession对应不同的一级缓存
2、同一个SqlSession但是查询条件不同
3、同一个SqlSession两次查询期间执行了任何一次增
删改操作
4、同一个SqlSession两次查询期间手动清空了缓存

二级缓存:
二级缓存默认不开启,需要手动配置
二级缓存在 SqlSession 关闭或提交之后才会生效
缓存实现要求
POJO实现Serializable接口
使用步骤
1、全局配置文件Mybatis.xml中开启二级缓存

 <setting name="cacheEnabled" value="true"/>

2、需要使用二级缓存的映射文件mapper.xml处使用cache配置缓存

<mapper namespace="com.kk.mapper.UserMapper">
    
	<cache eviction="FIFO" flushInterval="5000" readOnly="false" size="1024"></cache>
	</cache>

3、注意:POJO需要实现Serializable接口

public class User implements Serializable{
   
}

缓存相关属性
eviction=缓存回收策略
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU

flushInterval:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

size:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

缓存有关设置
1、全局setting的cacheEnable: – 配置二级缓存的开关。一级缓存一直是打开的。
2、select标签的useCache属性:
配置这个select是否使用二级缓存。一级缓存一直是使用的
3、sql标签的flushCache属性:
增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false。
4、sqlSession.clearCache(): 只是用来清除一级缓存。
5、当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所 有 select 中的缓存将被clear。

Mybatis也可以整合第三方缓存,例如EhCache
1:引入EhCachejar包

        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.0</version>
        </dependency>

2:导入与第三方缓存整合的适配包;官方有

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 <!-- 磁盘保存路径 -->
 <diskStore path="D:\kk\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="10000" 
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>

3:在mapper.xml中配置自定义cache

<mapper namespace="com.kk.mapper.UserMapper">
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

顺带提下Mybatis-Plus
其实和mybati基本没区别,多了些功能,主要是面对简单的业务场景,可以不用些mapper.xml了,框架帮你写好了,你主要继承提供的BaseMapper即可,还提供了分页,具体可以看看。

public interface EmplopyeeDao extends BaseMapper<Employee> {
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值