缓存通过减少IO(读写文件)的方式,来提高程序的执行效率。mybatis的缓存将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO,另一方面不再执行繁琐的查找算法,效率大大提升。
mybatis缓存包括:
缓存只针对于DQL语句,也就是说缓存机制只对应select语句
默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,如果执行2次相同的SQL查询,那么第二次SQL查询会直接取缓存的数据,而不是到数据库中查询,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会到数据库中查找数据。
一级缓存在下面情况会被清除
MappedStatement是指:一个CRUD标签在mybatis中会被封装成一个MappedStatement。
测试
mapper接口:
- //通过id查询汽车
- Car selectById(Long id);
mapper映射文件:
- <select id="selectById" resultType="Car">
- select * from t_car where id=#{id}
- select>
测试类: 使用的是同一个mapper
- //测试一级缓存
- @Test
- public void test1(){
- SqlSession sqlSession = SqlSessionUtil.openSession();
- CarMapper mapper = sqlSession.getMapper(CarMapper.class);
- Car car1 = mapper.selectById(194L);
- System.out.println(car1);
-
- Car car2 = mapper.selectById(194L);
- System.out.println(car2);
-
- //关闭
- sqlSession.close();
-
- }
测试结果:

执行相同的sql的时候,第二次没有执行sql语句,而是直接使用缓存!
换换测试方式:既然是在同一个sqlsession那么和创建的mapper应该没有什么关系吧
- //使用的是不同mapper(狗头保命sqlsession)
- @Test
- public void test2(){
- SqlSession sqlSession = SqlSessionUtil.openSession();
- CarMapper mapper = sqlSession.getMapper(CarMapper.class);
- Car car1 = mapper.selectById(194L);
- System.out.println(car1);
-
- Car car2 = mapper.selectById(194L);
- System.out.println(car2);
-
- //关闭
- sqlSession.close();
-
- }
测试结果 还是一个

获取不同的Sqlsession对象测试:
- @Test
- public void test3() throws IOException {
- SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
- SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));
- SqlSession sqlSession = sessionFactory.openSession();
- SqlSession sqlSession1 = sessionFactory.openSession();
- CarMapper mapper = sqlSession.getMapper(CarMapper.class);
- Car car = mapper.selectById(194L);
- System.out.println(car);
-
- CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
- Car car1 = mapper1.selectById(194L);
- System.out.println(car1);
- sqlSession.close();
- sqlSession1.close();
- }
测试结果:
测试的结果是使用的是两个sqlsession对象,所以导致这样的情况发生。由于只会存在同一个SQL Session的缓存,所以此次的查询使用啦两个sql语句。
默认关闭,可通过全局配置文件中的
使用二级缓存需要具备以下几个条件:
1、

2、在需要使用二级缓存的SqlMapper.xml文件中添加配置:

3、使用二级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接口

4、SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。
测试类:
- @Test
- public void test4() throws IOException {
- SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
-
- SqlSession sqlSession = sessionFactory.openSession();
- CarMapper mapper = sqlSession.getMapper(CarMapper.class);
- Car car = mapper.selectById2(194L);
- System.out.println(car);
- SqlSession sqlSession1 = sessionFactory.openSession();
- CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
- Car car1 = mapper1.selectById2(194L);
- System.out.println(car1);
-
-
- }
这里避免了一级缓存的情况,使用的不同sqlSession对象,但是没有关闭和提交所以应该是两条的sql语句。
测试结果:

执行的是两个sql语句!
那么将上面的测试的代码稍稍稍修改一下,然后体现二级缓存的功能!

关闭后才会将一级缓存存入二级缓存中,这样下一次执行相同的数据就会在缓存中获取查询结果。
测试结果:
触发二级缓存!只是执行啦一次的sql语句!
缓存机制:
执行sql语句后------存入一级缓存------存入二级缓存----再次执行sql------会先到一级缓存(没有)------然后到二级缓存(没有)------到数据库中
只要两个sql查询语句之间有DML操作执行,那么一级和二级缓存都会被清理!!!!
(1)eviction:指定从缓存中移除某个对象的淘汰算法。默认采用LRU策略。
1、LRU:Least Recently Used。最近最少使用。优先淘汰在间隔时间内使用频率最低的对象。(其实还有一种淘汰算法LFU,最不常用。)
2、FIFO:First In First Out。一种先进先出的数据缓存器。先进入二级缓存的对象最先被淘汰。
3、SOFT:软引用。淘汰软引用指向的对象。具体算法和JVM的垃圾回收算法有关。
4、WEAK:弱引用。淘汰弱引用指向的对象。具体算法和JVM的垃圾回收算法有关。
(2)flushInterval:二级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存足够大,一直会向二级缓存中缓存数据。除非执行了增删改。
(3)readOnly:
1、true:多条相同的sql语句执行之后返回的对象是共享的同一个。性能好。但是多线程并发可能会存在安全问题。
2、false:多条相同的sql语句执行之后返回的对象是副本,调用了clone方法。性能一般。但安全。
(4)size:设置二级缓存中最多可存储的java对象数量。默认值1024。
集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。mybatis对外提供了接口,也可以集成第三方的缓存组件。比如EhCache、Memcache等。都可以。EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操作,就可以完成集成:
导入依赖:
- <dependency>
- <groupId>org.mybatis.cachesgroupId>
- <artifactId>mybatis-ehcacheartifactId>
- <version>1.2.2version>
- dependency>
配置文件:
- "1.0" encoding="UTF-8"?>
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
- updateCheck="false">
-
- <diskStore path="e:/ehcache"/>
-
-
-
-
-
-
-
-
-
-
-
-
- <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
- timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
-
- ehcache>
引入第三方缓存:在XXXMapper.xml文件中
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
mybatis官方提供了mapper自动生成工具mybatis-generator-core来针对单表,生成PO类,以及Mapper接口和mapper.xml映射文件。针对单表,可以不需要再手动编写xml配置文件和mapper接口文件了,非常方便。美中不足的是它不支持生成关联查询,一般做关联查询,就自己单独写SQL就好了。
就是根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。
配置信息包含:
第一步导入依赖:
-
-
- <build>
-
- <plugins>
-
- <plugin>
-
- <groupId>org.mybatis.generatorgroupId>
- <artifactId>mybatis-generator-maven-pluginartifactId>
- <version>1.4.1version>
-
- <configuration>
- <overwrite>trueoverwrite>
- configuration>
-
- <dependencies>
-
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <version>8.0.30version>
- dependency>
- dependencies>
- plugin>
- plugins>
- build>
配置核心文件:
- "1.0" encoding="UTF-8"?>
- generatorConfiguration
- PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
- "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
-
- <generatorConfiguration>
-
- <context id="DB2Tables" targetRuntime="MyBatis3">
-
- <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
-
- <commentGenerator>
-
- <property name="suppressDate" value="true"/>
-
- <property name="suppressAllComments" value="true"/>
- commentGenerator>
-
-
- <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
- connectionURL="jdbc:mysql://localhost:3306/powernode"
- userId="root"
- password="root">
- jdbcConnection>
-
-
- <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
-
- <property name="enableSubPackages" value="true"/>
-
- <property name="trimStrings" value="true"/>
- javaModelGenerator>
-
-
- <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
-
- <property name="enableSubPackages" value="true"/>
- sqlMapGenerator>
-
-
- <javaClientGenerator
- type="xmlMapper"
- targetPackage="com.powernode.mybatis.mapper"
- targetProject="src/main/java">
- <property name="enableSubPackages" value="true"/>
- javaClientGenerator>
-
-
- <table tableName="t_car" domainObjectName="Car"/>
-
- context>
- generatorConfiguration>
使用插件生成文件:

然后在修修改改其他的配置信息就可以进行测试啦!
创建简单的sql语句我觉得就可以,对于负载的sql觉得使用起来并不方便
分页的参数介绍:
pageNum 当前页码
pageSize 显示信息数
totalcount 总记录数
totalPage 总页码
totalPage=totalCount % pageSize ==0? (totalCount % pageSize) : (totalCount % pageSize) +1 ;
分页展示的时候要使用 limit 分页查询 使用这个关键字要传递两个参数,第一个 start 就是开始的索引,然后是查询的条数,也就是pageSize,那么start怎么计算呐!
start=(pagaNum-1) * pageSize
第一步导入依赖
- <dependency>
- <groupId>com.github.pagehelpergroupId>
- <artifactId>pagehelperartifactId>
- <version>5.3.3version>
- dependency>
第二步在核心配置文件设置插件:
- <plugins>
- <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
- plugins>
mapper接口:
- //分页插件查询所有
- List
selectAll();
mapper映射文件:
- <select id="selectAll" resultType="Car">
- select * from t_car
- select>
这样看好像也没什么区别和之前的操作,是不是很迷惑!
测试类来啦:
- //使用分页插件
- @Test
- public void test2(){
- SqlSession sqlSession = SqlSessionUtil.openSession();
- CarMapper mapper = sqlSession.getMapper(CarMapper.class);
- //在执行DQL语句之前开启分页功能
- int pageNum=2;
- int pageSize=5;
- PageHelper.startPage(pageNum,pageSize);
- List
carList = mapper.selectAll(); - carList.forEach(System.out::println);
- sqlSession.close();
- }
另外说一下,pagehelper中可以将查询出来的数据封装到pageInfo中,然后这个对对象里面有很多的信息,真的就很牛 。节省很多功夫!这里有大概的数据展示可以了解一下!
- PageInfo{
- pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=6, pages=3,
- list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=6, pages=3, reasonable=false, pageSizeZero=false}
- [Car{id=86, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'},
- Car{id=87, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}],
- prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true,
- navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]
- }
mybatis中也提供了注解式开发方式,采用注解可以减少Sql映射文件的配置。但是使用注解式开发的话,sql语句是写在java程序中的,这种方式也会给sql语句的维护带来成本。
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
注解方式插入数据:
- //注解方式插入
- @Insert(value="insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
- int insert(Car car);
注解方式删除:
- @Delete("delete from t_car where id = #{id}")
- int deleteById(Long id);
注解方式修改:
- @Update("update t_car set car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} where id=#{id}")
- int update(Car car);
注解方式查询:
- @Select("select * from t_car where id = #{id}")
- @Results({
- @Result(column = "id", property = "id", id = true),
- @Result(column = "car_num", property = "carNum"),
- @Result(column = "brand", property = "brand"),
- @Result(column = "guide_price", property = "guidePrice"),
- @Result(column = "produce_time", property = "produceTime"),
- @Result(column = "car_type", property = "carType")
- })
- Car selectById(Long id);
多个参数的注解方式:
- @Select("SELECT * FROM student WHERE name like '%${name}%' AND major like '%${major}%'")
- List
find(@Param("name") String name, @Param("major") String major);