# MyBatis-10:高级特性

# 导航

回到mybatis导航页

# MyBatis日志管理

日志门面

logback要比log4j性能要好

# 引入logback

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
1
2
3
4
5

# 配置logback

在resources目录下新建logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <!--
    日志输出级别(优先级高到底):
    error:错误 - 系统的故障日志
    warn: 警告 - 存在风险或使用不当的日志
    info: 一般性日志
    debug: 程序内部用于调试信息
    trace:程序运行的跟踪信息
    一般开发环境,日志级别为:debug
    生产环境,为:info
    -->
    <root level="debug">
        <appender-ref ref="console"/>
    </root>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{10} - %msg%n</pattern>
        </encoder>
    </appender>
    <!--生产按天记录日志,一天一个日志文件-->
    <appender name="accessHisoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
     <fileNamePattern>d:/logs/history.%d.log</fileNamePattern>
    </rollingPolicy>
        <encoder>
            <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{10} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="console"/>
    </root>
    <logger name="com.torey.interception.interceptor.AccessHistoryInterceptor" leval="INFO" additivity="false">
        <appender-ref ref="accessHisoryLog"/>
    </logger>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 测试logback

再次执行testSelectAll方法,打印日志如下:


[main] 20:53:58.271 DEBUG o.a.i.d.pooled.PooledDataSource - Created connection 168907708.
[main] 20:53:58.271 DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@a1153bc]
[main] 20:53:58.274 DEBUG goods.selectAll - ==>  Preparing: SELECT * FROM t_goods ORDER BY goods_id limit 10 
[main] 20:53:58.335 DEBUG goods.selectAll - ==> Parameters: 
[main] 20:53:58.506 DEBUG goods.selectAll - <==      Total: 1

1
2
3
4
5
6
7

# 动态SQL

动态SQL是指根据参数数据动态组织SQL的技术

  where 1=1
             <if test="postId">
                 and u.post_id=#{postId}
             </if>
             <if test="deptId">
                 and u.dept_id=#{deptId}
             </if>
             <if test="userId">
                 and d.user_id=#{userId}
             </if>
             <if test="addOrReduce">
                 and d.add_or_reduce=#{addOrReduce}
             </if>
1
2
3
4
5
6
7
8
9
10
11
12
13

# MyBatis二级缓存

  • 一级缓存默认开启,缓存范围SqlSession会话
  • 二级缓存手动开启,属于范围Mapper Namespace

一级缓存使用率不高 MyBatis缓存

# 二级缓存运行规则

  • 二级开启后默认所有查询操作均使用缓存
  • 写操作commit提交时对该namespace缓存强制清空
  • 配置useCache=false可以不用缓存
  • 配置flushCache=true代表强制清空缓存

# 一级缓存测试

    /**
     * 测试一级缓存
     * @throws Exception
     */
    @Test
    public void testLv1Cache() throws Exception {
        SqlSession sqlSession=null;
        try{
            sqlSession = MyBatisUtils.openSession();
            TGoodsEntity tGoodsEntity = sqlSession.selectOne("goods.selectById",743);
            TGoodsEntity tGoodsEntity2 = sqlSession.selectOne("goods.selectById",743);
            System.out.println("========");
            //hashCode相等,证明是同一个对象
            System.out.println(tGoodsEntity.hashCode());
            System.out.println(tGoodsEntity2.hashCode());
            System.out.println("========");
        }catch (Exception ex){
            ex.printStackTrace();
            throw ex;
        }finally {
            if (null!=sqlSession) {
                MyBatisUtils.closeSession(sqlSession);
            }
        }
//不属于通一个sql session,所以会再次查询
        try{
            sqlSession = MyBatisUtils.openSession();
            TGoodsEntity tGoodsEntity = sqlSession.selectOne("goods.selectById",743);
            //commit提交时对该namespace缓存强制清空
            sqlSession.commit();
            TGoodsEntity tGoodsEntity2 = sqlSession.selectOne("goods.selectById",743);
            System.out.println("========");
            //hashCode相等,证明是同一个对象
            System.out.println(tGoodsEntity.hashCode());
            System.out.println(tGoodsEntity2.hashCode());
            System.out.println("========");
        }catch (Exception ex){
            ex.printStackTrace();
            throw ex;
        }finally {
            if (null!=sqlSession) {
                MyBatisUtils.closeSession(sqlSession);
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 开启二级缓存

合理使用二级缓存,对程序速度提升有很大的提升

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true" />
1

所有代码如下:

<?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="goods">
    <!--开启了二级缓存-->
    <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true" />
    <select id="selectById"
            resultType="com.torey.mybatis.entity.TGoodsEntity">
        SELECT * FROM t_goods WHERE goods_id=#{value}
    </select>
    <select id="selectByTitle"
            resultType="com.torey.mybatis.entity.TGoodsEntity">
        SELECT * FROM t_goods WHERE title=#{title}
    </select>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
     * 测试二级缓存
     * @throws Exception
     */
    @Test
    public void testLv2Cache() throws Exception {
        SqlSession sqlSession=null;
        try{
            sqlSession = MyBatisUtils.openSession();
            TGoodsEntity tGoodsEntity = sqlSession.selectOne("goods.selectById",743);
            //hashCode相等,证明是同一个对象
            System.out.println(tGoodsEntity.hashCode());
        }catch (Exception ex){
            ex.printStackTrace();
            throw ex;
        }finally {
            if (null!=sqlSession) {
                MyBatisUtils.closeSession(sqlSession);
            }
        }
//不属于通一个sql session,所以会再次查询
        try{
            sqlSession = MyBatisUtils.openSession();
            TGoodsEntity tGoodsEntity = sqlSession.selectOne("goods.selectById",743);
            System.out.println(tGoodsEntity.hashCode());
        }catch (Exception ex){
            ex.printStackTrace();
            throw ex;
        }finally {
            if (null!=sqlSession) {
                MyBatisUtils.closeSession(sqlSession);
            }
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

打印日志如下:

[main] 18:49:06.638 DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection
[main] 18:49:07.528 DEBUG o.a.i.d.pooled.PooledDataSource - Created connection 2009221452.
[main] 18:49:07.529 DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@77c2494c]
[main] 18:49:07.545 DEBUG goods.selectById - ==>  Preparing: SELECT * FROM t_goods WHERE goods_id=?
[main] 18:49:07.582 DEBUG goods.selectById - ==> Parameters: 743(Integer)
[main] 18:49:08.859 DEBUG goods.selectById - <==      Total: 1
1977310713
[main] 18:49:08.860 DEBUG o.a.i.t.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@77c2494c]
[main] 18:49:08.865 DEBUG o.a.i.t.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@77c2494c]
[main] 18:49:08.865 DEBUG o.a.i.d.pooled.PooledDataSource - Returned connection 2009221452 to pool.
[main] 18:49:08.865 DEBUG goods - Cache Hit Ratio [goods]: 0.5
1977310713
1
2
3
4
5
6
7
8
9
10
11
12

# 二级缓存详情

# cache命令详解

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true" />
1
# eviction

是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除,选项如下:

  • LRU: 最近最久未使用:移除最长时间不被使用的对象(实际项目中就用这个,以下3个一般不使用)
  • FIFO: 先进先出:按对象进入缓存的顺序来移除它们
  • SOFT: 软引用:移除基于垃圾收集器状态和软引用规则的对象
  • WEAK: 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象
# flushInterval

flushInterval 代表间隔多长时间自动清空缓存,单位毫秒,600000毫秒=10分钟,可以相对的设置长一些,比如 1小时

# size

size: 缓存存储的上限,用于保存对象或者集合(一个集合算一个对象)的数量上限

# readOnly

readOnly 设置为true:代表返回的是只读缓存,每次从缓存取出的是缓存对象本身,这种执行效率较高,一般设置为true
readOnly 设置为false: 代表每次取出的是缓存对象的“副本”,每一次取出的对象都是不同的,这种安全性较高

# 设置某个查询语句不被缓存

像一般的一个sql查询出多条语句的时候,就尽量不要缓存,因为命中率并不高,那么这时候设置:useCache="false",就不会被缓存

# 立即清理缓存

flushCache="true" ,sql语句执行完后强制清空缓存,既可以用在写操作上,也可以用到读操作,也就是select

<insert id="add" flushCache="true">
...
    </insert>
1
2
3
<select id="selectByList" resultType="com.torey.mybatis.entity.TGoodsEntity" useCache="false">
        select * from t_goods
    </select>
1
2
3

# 导航,上一页,下一页

9MyBatis预防SQL注入攻击
12OneToMany对象关联查询

# 支持我-微信扫一扫-加入微信公众号

Aseven公众号

# 赞赏作者

赞赏作者