1.动态SQL(核心)1.1简介
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的难点问题。
比如: 我们在多条件查询的时候会写这样的语句:
select * from sys_user where 1=1 and
再比如:做更新的时候,我们没有修改的数据列也执行了更新操作。
1.2 if和where标签
<!– List select ByCondition(Emp emp); –> select emp_id,emp_name,emp_salary from sys_emp <!– where标签会自动去掉“标签体内前面、后面多余的and/or” –> <!– 使用if标签,让我们可以有选择的加入SQL语句的片段。这个SQL语句片段是否要加入整个SQL语句,就看if标签判断的结果是否为true –> <!– 在if标签的test属性中,可以访问实体类的属性,不可以访问数据库表的字段 –> <!– 在if标签内部,需要访问接口的参数时还是正常写#{} –> or emp_name=#{empName} 2000″> or emp_salary>#{empSalary} <!– 第一种情况:所有条件都满足 WHERE emp_name=? or emp_salary>? 第二种情况:部分条件满足 WHERE emp_salary>? 第三种情况:所有条件都不满足 没有where子句 –> |
1.3 set标签
需求:实际开发时,对一个实体类对象进行更新。往往不是更新所有字段,而是更新一部分字段。此时页面上的表单往往不会给不修改的字段提供表单项。
例如:上面的表单,如果服务器端接收表单时,使用的是User这个实体类,那么userName、userBalance、userGrade接收到的数据就是null 。
如果不加判断,直接用User对象去更新数据库,在Mapper配置文件中又是每一个字段都更新,那就会把userName、userBalance、userGrade设置为null值,从而造成数据库表中对应数据被破坏。
此时需要我们在Mapper配置文件中,对update语句的set子句进行定制,此时就可以使用动态SQL的set标签。
<!– void updateeDynamic(Empemp) –> update sys_emp <!– 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 –> emp_name=#{empName}, <iftest="empSalary emp_salary=#{empSalary}, where emp_id=#{empId} |
第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?
第二种情况:部分条件满足 SET emp_salary=?
第三种情况:所有条件都不满足 update t_emp where emp_id=?
没有set子句的update语句会导致SQL语法错误
1.4trim标签
使用trim标签控制条件部分两端是否包含某些字符
prefix属性:指定要动态添加的前缀内容
suffix属性:指定要动态添加的后缀
prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
下面例子中,trim标签内部如果有条件,则where会出现,否则where不出现。
suffixOverrides=“and|or”:整个条件部分,如果在后面有多出来的“and或or”会被自动去掉。
<!– List selectByConditionByTrim(Emp emp) –> select emp_id,emp_name,emp_age,emp_salary,emp_gender from sys_emp <!– prefix属性指定要动态添加的前缀 –> <!– suffix属性指定要动态添加的后缀 –> <!– prefixOverrides属性指定要动态去掉的前缀,使用“|”分隔有可能的多个值 –> <!– suffixOverrides属性指定要动态去掉的后缀,使用“|”分隔有可能的多个值 –> <!– 当前例子用where标签实现更简洁,但是trim标签更灵活,可以用在任何有需要的地方 –> emp_name=#{empName} and <iftest="empSalary >3000″> emp_salary > #{empSalary} and <iftest="empAge emp_age=#{empAge} or emp_gender=#{empGender} |
1.5choose/when/otherwise标签
在多个分支条件中,仅执行一个。
<!– List selectByConditionByChoose(Emp emp) –> select emp_id,emp_name,emp_salary from sys_emp where emp_name=#{empName} 3000″>emp_salary >3000 1=1 <!– 第一种情况:第一个when满足条件 where emp_name=? 第二种情况:第二个when满足条件 where emp_salary < 3000 第三种情况:两个when都不满足 where 1=1 执行了otherwise –> |
1.6 foreach标签1.6.1 基本用法
比如:批量插入
abstract public void insertBatch(@Param(“empList”)List empList));
<!– INSERT INTO `sys_emp` VALUES (null, ‘李冰冰‘, ‘lbb‘, ‘f’, 300,default,2), (null, ‘张彬彬‘, ‘zbb‘, ‘m’, 599,default,3), (null, ‘万茜‘, ‘wq‘, ‘m’, 4000,default,1), (null, ‘李若彤‘, ‘lrt‘, ‘m’, 5000.8,default,1) –> <insertid=“insertBatch”> INSERT INTO `sys_emp`(emp_id,emp_name,emp_gender) <foreachcollection=“empList”item=“emp”separator=“,”open=“VALUES”> (null,#{emp.empName},#{emp.empGender}) |
我们这里写的批量插入的例子本质上是一条SQL语句。
collection属性:要遍历的集合,如果接口中方法中使用了@Param ,collection属性中要用这个名字。
item属性:遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象
separator属性:指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
open属性:指定整个foreach循环把字符串拼好后,这个字符串整体的前面要添加的字符串
close属性:指定整个foreach循环把字符串拼好后,这个字符串整体的后面要添加的字符串
index属性:这里起一个名字,便于后面引用
遍历List集合,这里能够得到List集合的索引值
遍历Map集合,这里能够得到Map集合的key
如果接口形参位置没有使用@Param注解,而且foreach标签也没有使用默认的名称,则会抛出异常
Causedby:org.apache.ibatis.binding.BindingException: Parameter ‘empList’ not found. Available parameters are[arg0,collection, list]
1.6.2 批量更新
而实现批量更新则需要多条update SQL语句拼起来,并且用分号分开。也就是一次性发送多条SQL语句让数据库执行。
此时需要在数据库连接信息的URL地址中设置
?allowMultiQueries=true
对应的foreach标签如下:
<!– int updateBatch(@Param("empList") List empList) –>
update sys_emp set emp_name=#{emp.empName} where emp_id=#{emp.empId}
1.6.3 关于foreach标签的collection属性
如果没有给接口中List类型的参数使用@Param注解指定一个具体的名字,那么在collection属性中默认可以使用collection或list来引用这个list集合。这一点可以通过异常信息看出来:
Parameter’empList’notfound. Availableparametersare[collection, list]
在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@Param注解明确声明变量的名称,然后在foreach标签的collection属性中按照@Param注解指定的名称来引用传入的参数。
1.7 sql标签1.7.1 抽取重复的SQL片段
<!– 使用sql标签抽取重复出现的SQL片段 –> select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp |
1.7.2 引用已抽取的SQL片段
<!– 使用include标签引用声明的SQL片段 –> |
2.缓存2.1 缓存机制
比如:以前农村装水的水缸
2.2 一级缓存和二级缓存
二级缓存被所有的SqlSession共享,也就是能被访问的。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是Mapper(namespace)级别的缓存。多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
第一次查询,先将结果放入到一级缓存,等SqlSession提交事务后,再将数据放入到二级缓存。
2.2.1 一级缓存和二级缓存的使用顺序
查询的顺序是:
1)先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
2)如果二级缓存没有命中,再查询一级缓存
3)如果一级缓存也没有命中,则查询数据库
SqlSession关闭之前,会将一级缓存中的数据会写入二级缓存
2.2.2 效用范围
一级缓存:SqlSession级别
二级缓存:SqlSessionFactory级别
它们之间范围的大小参考下面图:
一个请求中可能包含多个事务——一个service方法(一个SqlSession)对应一个事务
注意:缓存是用再查询过程中的,增删改,反而会破坏缓存。造成缓存和数据库不一致,所以很多情况,执行了一个增删改操作,他会把缓存清空。
3. 一级缓存
Mybatis默认开启了一级缓存
3.1 案例1:测试一级缓存是否存在
为了测试缓存失效,我们需要修改测试类中的代码。需要关闭SqlSessioin对象,然后重新开,再重新开的话,需要操作SqlSessionFactory。
如何测试一级缓存是否存在???同一个数据查两次,但是只发了一条SQL语句[给数据库]。
3.1.1 证明一级缓存存在
packagecom.hy.mybatis.test; importjava.io.IOException; importorg.apache.ibatis.io.Resources; importorg.apache.ibatis.session.SqlSession; importorg.apache.ibatis.session.SqlSessionFactory; importorg.apache.ibatis.session.SqlSessionFactoryBuilder; importorg.junit.Before; importorg.junit.Test; importcom.hy.bean.Emp; importcom.hy.mapper.EmpMapper; publicclassTestLevelOneCache1 { privateSqlSessionFactory sqlSessionFactory; privateLogger logger= null; @Before publicvoidinit() throwsIOException { logger= LoggerFactory.getLogger(this.getClass()); sqlSessionFactory= newSqlSessionFactoryBuilder().build(Resources.getResourceAsStream(“mybatis-config.xml”)); } @Test publicvoidtestLevelOneCache1_01() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); Emp emp2= empMapper.selectById(1); // 第二次是从缓存中查询出来的。 logger.info(“是否相等:”+ (emp1== emp2)); //true session.commit(); session.close(); } } |
只发一条SQL语句。一级缓存默认开启,不需要做额外的配置。二级缓存需要开启才有,现在没有开,所以只有一级缓存。
3.2 案例2:一级缓存失效的情况:
1)同一个SqlSession两次查询期间提交了事务
2)同一个SqlSession两次查询期间执行了任何一次增删改操作,不论是够提交事务,都清空一级缓存
3)同一个SqlSession但是查询条件发生了变化
4)同一个SqlSession两次查询期间手动清空了缓存
5)不是同一个SqlSession
总结:在执行commit,rollback时会清空一级缓存
一级缓存的清除还有以下两个地方:
1、就是获取缓存之前会先进行判断用户是否配置了flushCache=true属性(参考一级缓存的创建代码截图),如果配置了则会清除一级缓存。 2、MyBatis全局配置属性localCacheScope配置为Statement时,那么完成一次查询就会清除缓存。 |
3.2.1 同一个SqlSession两次查询期间提交了事务
publicclassTestLevelCache1 { privateSqlSessionFactory sqlSessionFactory; privateLogger logger= null; @Before publicvoidinit() throwsIOException { logger= LoggerFactory.getLogger(this.getClass()); sqlSessionFactory= newSqlSessionFactoryBuilder().build(Resources.getResourceAsStream(“mybatis-config.xml”)); } //1) 同一个SqlSession两次查询期间提交了事务 //1.1 没有提交事务,使用一级缓存 @Test publicvoidtestLevelOneCache1_01() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); Emp emp2= empMapper.selectById(1); // 第二次是从缓存中查询出来的。 logger.info(“是否相等:”+ (emp1== emp2)); //true session.commit(); session.close(); } //1.2 两次查询中间,提交了事务,清空一级缓存 @Test publicvoidtestLevelOneCache1_02() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); session.commit(); Emp emp2= empMapper.selectById(1); // 由于进行了事务的提交,所以又发送了一条查询语句。 logger.info(“是否相等:”+ (emp1== emp2)); //false session.close(); } } |
3.2.2 同一个SqlSession两次查询期间执行了任何一次增删改操作,并且提交了事务
@Test publicvoidtestLevelOneCache01_4() { SqlSession sqlSession= sqlSessionFactory.openSession(); EmpMapper empMapper= sqlSession.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); //EmpnewEmp = new Emp(2L, “范冰冰ILoveYou”, null, null, null, null); //empMapper.updateById(newEmp); //更新但是不提交事务 empMapper.deleteById(8); //执行了删除没有,提交事务也,重新一遍 Emp emp2= empMapper.selectById(1); //logger.debug(emp2.toString()); logger.debug(“是否相等:”+ (emp1== emp2)); sqlSession.commit(); sqlSession.close(); } |
// 2.2 @Test publicvoidtestLevelOneCache2_02() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); //查询后,将对象放入一级缓存 empMapper.deleteById(7); //执行了delete操作,但是并没有提交 session.commit(); Emp emp11= empMapper.selectById(1); //提交了事务,一级缓存清空 logger.info(“是否相等:”+ (emp1== emp11)); //false session.commit(); session.close(); } |
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息,将查询到的用户信息存储到一级缓存中。
如果中间sqlSession去执行插入、更新、删除,并且commit,清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。如果没有,则重新发出一条查询语句。
3.2.3 同一个SqlSession但是查询条件发生了变化
// 3. 同一个SqlSession但是查询条件发生了变化 @Test publicvoidtestLevelOneCache3_01() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); //查询后,将对象放入一级缓存 //查询的是emp_id为2的员工信息,一级缓存中并没有所以重新发出一条SQL语句 Emp emp2= empMapper.selectById(2); session.commit(); session.close(); } |
3.2.4 同一个SqlSession两次查询期间手动清空了缓存
// 4)同一个SqlSession两次查询期间手动清空了缓存 @Test publicvoidtestLevelOneCache4() throwsIOException { SqlSession session= sqlSessionFactory.openSession(); EmpMapper empMapper= session.getMapper(EmpMapper.class); Emp emp1= empMapper.selectById(1); session.clearCache(); Emp emp2= empMapper.selectById(1); // 由于两次查询中间清空了一级缓存,所以又发送了一条查询语句。 logger.info(“是否相等:”+ (emp1== emp2)); //false session.commit(); session.close(); } |
3.2.5 不是同一个SqlSession
// 5)不是同一个SqlSession @Test publicvoidtestLevelOneCache1_05() throwsIOException { SqlSession session01= sqlSessionFactory.openSession(); SqlSession session02= sqlSessionFactory.openSession(); EmpMapper empMapper01= session01.getMapper(EmpMapper.class); EmpMapper empMapper02= session02.getMapper(EmpMapper.class); Emp emp1= empMapper01.selectById(1); // 由于是不同的SqlSession,所以又发送了一条查询语句。各自有各自的一级缓存。 Emp emp2= empMapper02.selectById(1); logger.info(“是否相等:”+ (emp1== emp2)); //false session01.commit(); session02.commit(); session01.close(); session02.close(); } |
4. 二级缓存[mybatis自带的二级缓存]
4.1 使用二级缓存步骤1)在想要使用二级缓存的EmpMapper映射文件中加入cache标签
开启全局二级缓存配置:
2)让实体类支持序列化
publicclassEmp implementsSerializable{
privatestaticfinallongserialVersionUID= 1L;
这里我们使用mybaits自带的二级缓存,后面我们使用第三方的二级缓存EHCache。
3)SqlSession提交事务时才会将查询到的数据存入二级缓存
@Test publicvoidtestLevelTwoCache() { // 测试二级缓存存在:使用两个不同SqlSession执行查询 // 说明:SqlSession提交事务时才会将查询到的数据存入二级缓存 // 所以本例并没有能够成功从二级缓存获取到数据 SqlSession sqlSession01= sqlSessionFactory.openSession(); SqlSession sqlSession02= sqlSessionFactory.openSession(); EmpMapper empMapper01= sqlSession01.getMapper(EmpMapper.class); EmpMapper empMapper02= sqlSession02.getMapper(EmpMapper.class); //[00:01:07.699] [DEBUG] [main] [com.hy.mapper.EmpMapper] [Cache Hit Ratio [com.hy.mapper.EmpMapper]: 0.0] Emp emp01= empMapper01.selectById(1); //[00:01:07.746] [DEBUG] [main] [com.hy.mapper.EmpMapper] [Cache Hit Ratio [com.hy.mapper.EmpMapper]: 0.0] Emp emp02= empMapper02.selectById(1); logger.info(“是否相等:”+ (emp1== emp2)); //false sqlSession01.commit(); sqlSession01.close(); sqlSession02.commit(); sqlSession02.close(); } |
修改代码;
@Test publicvoidtestSecondLevelCache2() { SqlSession sqlSession01= sqlSessionFactory.openSession(); SqlSession sqlSession02= sqlSessionFactory.openSession(); EmpMapper empMapper01= sqlSession01.getMapper(EmpMapper.class); EmpMapper empMapper02= sqlSession02.getMapper(EmpMapper.class); Emp emp01= empMapper01.selectById(1); sqlSession01.commit(); sqlSession01.close(); Emp emp02= empMapper02.selectById(1); //false注意,从二级缓存中new了一个新的对象,所以emp01和emp02不是同一个对象 logger.info(“是否相等:”+ (emp1== emp2)); sqlSession02.commit(); sqlSession02.close(); } |
虽然两个对象不相等,但是注意:只发出了一条查询语句。
日志中打印的Cache Hit Ratio叫做缓存命中率
缓存命中率=命中缓存的次数/查询的总次数
4)mybatis序列化的特点
mybatis的二级缓存是属于序列化,序列化的意思就是从内存中的数据传到硬盘中,这个过程就是序列化;
反序列化意思就是相反而已;
也就是说,mybatis的二级缓存,实际上就是将数据放进了硬盘文件中去了;
现在呢,你仅仅的将Emp类给序列化了,如果有父类Person、级联属性,它们是不会跟着被序列化的,所以光这些是不够的;
很简单,如果Emp需要序列化,但是这个类中还有其他类的属性,仅需将其他类也实现序列化接口即可!
比如Emp类继承了Person父类,那么父类也需要实现Serializable这个接口;
4.2 二级缓存失效的条件
与一级缓存一样,二级缓存也会存在失效的条件的,下面我们就来探究一下哪些情况会造成二级缓存失效。
4.2.1 第一次SqlSession 未提交
SqlSession 在未提交的时候,SQL 语句产生的查询结果还没有放入二级缓存中,这个时候 SqlSession2 在查询的时候是感受不到二级缓存的存在的
4.2.2 更新对二级缓存影响
与一级缓存一样,更新操作对二级缓存造成影响,下面用三个 SqlSession来进行模拟,第一个 SqlSession 只是单纯的查询并提交,第二个 SqlSession 用于查询二级缓存是否失效,第三个 SqlSession2用于执行更新操作。
@Test publicvoidtestLevelTwoCache01_03() { SqlSession sqlSession1= sqlSessionFactory.openSession(); SqlSession sqlSession2= sqlSessionFactory.openSession(); SqlSession sqlSession3= sqlSessionFactory.openSession(); EmpMapper empMapper1= sqlSession1.getMapper(EmpMapper.class); EmpMapper empMapper2= sqlSession2.getMapper(EmpMapper.class); EmpMapper empMapper3= sqlSession3.getMapper(EmpMapper.class); Emp emp1= empMapper1.selectById(1); logger.info(emp1.toString()); sqlSession1.commit(); //清空一级缓存,加入二级缓存 Emp emp2= empMapper2.selectById(1); logger.info(emp2.toString()); //从二级缓存中查询出来 logger.info(“是否是同一个对象:”+(emp1==emp2)); sqlSession2.commit(); Emp newEmp= newEmp(1L,”垃圾张文宏“,null,null,null,null); empMapper3.updateById(newEmp); sqlSession3.commit(); Emp emp22= empMapper2.selectById(1); logger.info(emp22.toString()); //从二级缓存中查询出来 logger.info(“是否是同一个对象:”+(emp1==emp22)); sqlSession2.commit(); sqlSession1.close(); sqlSession2.close(); } |
因为所有的insert,delete,uptede都会触发缓存的刷新,从而导致二级缓存失效,所以二级缓存适合在读多写少的场景中开启。
1) 每个增删改标签都有默认清空缓存配置:flushCache=”true”,不过这是默认的是一级和二级缓存都清空 2)每个select标签都默认配置了useCache=”true”: |
4.2.3 测试时的问题
测试的时候,sqlSessionFactory不同,自然也会导致二级缓存失效。
4.2.4 测试时的问题
@Test publicvoidtestLevelTwoCache04() { SqlSession sqlSession01= sqlSessionFactory.openSession(); SqlSession sqlSession02= sqlSessionFactory.openSession(); SqlSession sqlSession03= sqlSessionFactory.openSession(); EmpMapper empMapper01= sqlSession01.getMapper(EmpMapper.class); EmpMapper empMapper02= sqlSession02.getMapper(EmpMapper.class); EmpMapper empMapper03= sqlSession03.getMapper(EmpMapper.class); Emp emp01= empMapper01.selectById(1); System.out.println(emp01); Emp newEmp= newEmp(1L, “范冰冰“, “fbbfbb”, null, null, null, null,null); empMapper02.updateByCondition(newEmp); sqlSession02.commit(); sqlSession02.close(); Emp emp02= empMapper01.selectById(1); System.out.println(emp02); System.out.println(emp01== emp02); } [com.hy.mapper.EmpMapper] [Cache Hit Ratio [com.hy.mapper.EmpMapper]: 0.0] [com.hy.mapper.EmpMapper.selectById] [==> Preparing: select * from sys_emp where emp_id = ?] [com.hy.mapper.EmpMapper.selectById] [==> Parameters: 1(Long)] [com.hy.mapper.EmpMapper.selectById] [<== Total: 1] Emp [empId=1, empName=范冰冰222, empPwd=fbb, empGender=f, empSalary=30000.0, empStatus=y [com.hy.mapper.EmpMapper.updateByCondition] [==> Preparing: update sys_emp SET emp_name = ? where emp_id = ?] [com.hy.mapper.EmpMapper.updateByCondition] [==> Parameters: 范冰冰(String), 1(Long)] [com.hy.mapper.EmpMapper.updateByCondition] [<== Updates: 1] [com.hy.mapper.EmpMapper] [Cache Hit Ratio [com.hy.mapper.EmpMapper]: 0.0] Emp [empId=1, empName=范冰冰222, empPwd=fbb, empGender=f, empSalary=30000.0, empStatus=y true |
4.3 二级缓存应该开启吗
一级缓存默认是开启的,而二级缓存是需要我们手动开启的,那么我们什么时候应该开启二级缓存呢?
1、因为所有的(insert,delete,uptede)都会触发缓存的刷新,从而导致二级缓存失效,所以二级缓存适合在读多写少的场景中开启。
2、因为二级缓存针对的是同一个namespace,所以建议是在单表操作的Mapper中使用,或者是在相关表的Mapper文件中共享同一个缓存。
5 EHCache缓存
5.1 EHCache简介
第三方的缓存产品
官网地址:https://www.ehcache.org/
5.2 整合操作
<!– MybatisEHCache整合包 –> org.mybatis.caches mybatis-ehcache 1.2.1 ch.qos.logback logback-classic 1.2.3 |
2.5.2.1 Mybatis环境
在Mybatis环境下整合EHCache,前提当然是要先准备好Mybatis的环境。
<projectxmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”> 4.0.0 com.hy springmvc006 0.0.1 war UTF-8 UTF-8 UTF-8 org.projectlombok lombok 1.18.20 <!– 数据库连接池 –> com.alibaba druid 1.2.9 com.fasterxml.jackson.core jackson-databind 2.12.1 <!– mybaits相关jar包 –> org.mybatis mybatis 3.5.6 <!– MybatisEHCache整合包 –> org.mybatis.caches mybatis-ehcache 1.2.1 <!– logback日志 slf4j日志门面的一个具体实现 –> ch.qos.logback logback-classic 1.2.3 junit junit 4.12 test mysql mysql-connector-java 5.1.49 <!– mybaits相关jar包 –> <!– 指定jdk,防止update project –> org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 <!– 项目编码 –> UTF-8 |
这是一个EHCache和mybatis的整合包,但是会讲EHCache核心包传递进来。
2.5.2.2 各主要jar包
作用2.5.2.3 整合EHCache
创建EHCache配置文件,ehcache.xml
<?xmlversion=“1.0”encoding=“utf-8”?> <ehcachexmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=“../config/ehcache.xsd”> <!– 磁盘保存路径 –> <diskStorepath=“f:\hy\ehcache”/> <defaultCache maxElementsInMemory=“1000” maxElementsOnDisk=“10000000” eternal=“false” overflowToDisk=“true” timeToIdleSeconds=“120” timeToLiveSeconds=“120” diskExpiryThreadIntervalSeconds=“120” memoryStoreEvictionPolicy=“LRU”> |
2.5.2.4 指定缓存管理器的具体类型
还是到查询操作所的EmpMapper配置文件中,找到之前设置的cache标签:
logback.xml
<?xmlversion=“1.0”encoding=“UTF-8”?> <configurationdebug=“true”> <!– 指定日志输出的位置 –> <appendername=“STDOUT” class=“ch.qos.logback.core.ConsoleAppender”> <!– 日志输出的格式 –> <!– 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 –> [%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n <!– 设置全局日志级别。日志级别按顺序分别是:TRACE > DEBUG > INFO > WARN > ERROR > FATAL –> <!– 指定任何一个日志级别都只打印当前级别和后面级别的日志。 –> <rootlevel=“DEBUG“> <!– 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender –> <appender-refref=“STDOUT”/> <!– 根据特殊需求指定局部日志级别 –> <loggername=“com.hy.mapper”level=“DEBUG”/> |
5.3 EHCache配置文件说明
改成10秒,10秒后释放。