• MyBatis(下)


    1、MayBatis的缓存:

            缓存通过减少IO(读写文件)的方式,来提高程序的执行效率。mybatis的缓存将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO,另一方面不再执行繁琐的查找算法,效率大大提升。

    mybatis缓存包括:

    • 一级缓存:将查询到的数据存储到SqlSession中。(当前的会话)
    • 二级缓存:将查询到的数据存储到SqlSessionFactory中。(对于整个数据库)
    • 或者集成其它第三方的缓存:比如EhCache【Java语言开发的】、Memcache【C语言开发的】等。

    缓存只针对于DQL语句,也就是说缓存机制只对应select语句

    (1)一级缓存:

            默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,如果执行2次相同的SQL查询,那么第二次SQL查询会直接取缓存的数据,而不是到数据库中查询,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会到数据库中查找数据。

    一级缓存在下面情况会被清除

    1. 在同一个SqlSession下执行增删改操作时(不必提交),会清除一级缓存(DML的操作和表没有关系,即使操作的不是同一个表也会触发这操作!)
    2. SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
    3. 对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效,在全局配置文件中设置 ,这样会使一级缓存失效,二级缓存不受影响
    4. 执行sqlSession的clearCache(),方法后一级缓存会被清空(手动清空缓存)

    MappedStatement是指:一个CRUD标签在mybatis中会被封装成一个MappedStatement。

    测试

    mapper接口: 

    1. //通过id查询汽车
    2. Car selectById(Long id);

    mapper映射文件:

    1. <select id="selectById" resultType="Car">
    2. select * from t_car where id=#{id}
    3. select>

    测试类:  使用的是同一个mapper

    1. //测试一级缓存
    2. @Test
    3. public void test1(){
    4. SqlSession sqlSession = SqlSessionUtil.openSession();
    5. CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    6. Car car1 = mapper.selectById(194L);
    7. System.out.println(car1);
    8. Car car2 = mapper.selectById(194L);
    9. System.out.println(car2);
    10. //关闭
    11. sqlSession.close();
    12. }

    测试结果:

    执行相同的sql的时候,第二次没有执行sql语句,而是直接使用缓存! 

    换换测试方式:既然是在同一个sqlsession那么和创建的mapper应该没有什么关系吧

    1. //使用的是不同mapper(狗头保命sqlsession)
    2. @Test
    3. public void test2(){
    4. SqlSession sqlSession = SqlSessionUtil.openSession();
    5. CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    6. Car car1 = mapper.selectById(194L);
    7. System.out.println(car1);
    8. Car car2 = mapper.selectById(194L);
    9. System.out.println(car2);
    10. //关闭
    11. sqlSession.close();
    12. }

     测试结果 还是一个

    获取不同的Sqlsession对象测试:

    1. @Test
    2. public void test3() throws IOException {
    3. SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
    4. SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));
    5. SqlSession sqlSession = sessionFactory.openSession();
    6. SqlSession sqlSession1 = sessionFactory.openSession();
    7. CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    8. Car car = mapper.selectById(194L);
    9. System.out.println(car);
    10. CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
    11. Car car1 = mapper1.selectById(194L);
    12. System.out.println(car1);
    13. sqlSession.close();
    14. sqlSession1.close();
    15. }

     测试结果:

            测试的结果是使用的是两个sqlsession对象,所以导致这样的情况发生。由于只会存在同一个SQL Session的缓存,所以此次的查询使用啦两个sql语句。

    (2)二级缓存:

            默认关闭,可通过全局配置文件中的开启二级缓存总开关,然后在某个具体的mapper.xml中增加,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交或者关闭,查询的数据才会被刷新到二级缓存当中。

    使用二级缓存需要具备以下几个条件:

    1、 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认就是true,无需设置。

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

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

    4、SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。

    测试类:

    1. @Test
    2. public void test4() throws IOException {
    3. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
    4. SqlSession sqlSession = sessionFactory.openSession();
    5. CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    6. Car car = mapper.selectById2(194L);
    7. System.out.println(car);
    8. SqlSession sqlSession1 = sessionFactory.openSession();
    9. CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
    10. Car car1 = mapper1.selectById2(194L);
    11. System.out.println(car1);
    12. }

             这里避免了一级缓存的情况,使用的不同sqlSession对象,但是没有关闭和提交所以应该是两条的sql语句。

    测试结果:

    执行的是两个sql语句!

    那么将上面的测试的代码稍稍稍修改一下,然后体现二级缓存的功能!

     

            关闭后才会将一级缓存存入二级缓存中,这样下一次执行相同的数据就会在缓存中获取查询结果。 

    测试结果:

     触发二级缓存!只是执行啦一次的sql语句!

    缓存机制:

            执行sql语句后------存入一级缓存------存入二级缓存----再次执行sql------会先到一级缓存(没有)------然后到二级缓存(没有)------到数据库中 

    只要两个sql查询语句之间有DML操作执行,那么一级和二级缓存都会被清理!!!!

    (3)二级缓存的相关配置:

    (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。

    (4)使用第三方缓存:

            集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。mybatis对外提供了接口,也可以集成第三方的缓存组件。比如EhCache、Memcache等。都可以。EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操作,就可以完成集成:

    导入依赖:

    1. <dependency>
    2. <groupId>org.mybatis.cachesgroupId>
    3. <artifactId>mybatis-ehcacheartifactId>
    4. <version>1.2.2version>
    5. dependency>

    配置文件:

    1. "1.0" encoding="UTF-8"?>
    2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    4. updateCheck="false">
    5. <diskStore path="e:/ehcache"/>
    6. <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
    7. timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    8. ehcache>

    引入第三方缓存:在XXXMapper.xml文件中

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

    2、MyBatis的逆向工程:

            mybatis官方提供了mapper自动生成工具mybatis-generator-core来针对单表,生成PO类,以及Mapper接口和mapper.xml映射文件。针对单表,可以不需要再手动编写xml配置文件和mapper接口文件了,非常方便。美中不足的是它不支持生成关联查询,一般做关联查询,就自己单独写SQL就好了。

            就是根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。

    配置信息包含:

    • pojo类名、包名以及生成位置。
    • SqlMapper.xml文件名以及生成位置。
    • Mapper接口名以及生成位置。
    • 连接数据库的信息。
    • 指定哪些表参与逆向工程。

    第一步导入依赖:

    1. <build>
    2. <plugins>
    3. <plugin>
    4. <groupId>org.mybatis.generatorgroupId>
    5. <artifactId>mybatis-generator-maven-pluginartifactId>
    6. <version>1.4.1version>
    7. <configuration>
    8. <overwrite>trueoverwrite>
    9. configuration>
    10. <dependencies>
    11. <dependency>
    12. <groupId>mysqlgroupId>
    13. <artifactId>mysql-connector-javaartifactId>
    14. <version>8.0.30version>
    15. dependency>
    16. dependencies>
    17. plugin>
    18. plugins>
    19. build>

    配置核心文件:

    1. "1.0" encoding="UTF-8"?>
    2. generatorConfiguration
    3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    5. <generatorConfiguration>
    6. <context id="DB2Tables" targetRuntime="MyBatis3">
    7. <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
    8. <commentGenerator>
    9. <property name="suppressDate" value="true"/>
    10. <property name="suppressAllComments" value="true"/>
    11. commentGenerator>
    12. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    13. connectionURL="jdbc:mysql://localhost:3306/powernode"
    14. userId="root"
    15. password="root">
    16. jdbcConnection>
    17. <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
    18. <property name="enableSubPackages" value="true"/>
    19. <property name="trimStrings" value="true"/>
    20. javaModelGenerator>
    21. <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
    22. <property name="enableSubPackages" value="true"/>
    23. sqlMapGenerator>
    24. <javaClientGenerator
    25. type="xmlMapper"
    26. targetPackage="com.powernode.mybatis.mapper"
    27. targetProject="src/main/java">
    28. <property name="enableSubPackages" value="true"/>
    29. javaClientGenerator>
    30. <table tableName="t_car" domainObjectName="Car"/>
    31. context>
    32. generatorConfiguration>

    使用插件生成文件:

     然后在修修改改其他的配置信息就可以进行测试啦!

    创建简单的sql语句我觉得就可以,对于负载的sql觉得使用起来并不方便

    3、MyBatis使用PageHelper分页插件:

    分页的参数介绍:

    pageNum           当前页码

    pageSize            显示信息数

    totalcount           总记录数

    totalPage           总页码  

    totalPage=totalCount % pageSize ==0?   (totalCount % pageSize) : (totalCount % pageSize) +1 ;

    分页展示的时候要使用 limit  分页查询   使用这个关键字要传递两个参数,第一个 start 就是开始的索引,然后是查询的条数,也就是pageSize,那么start怎么计算呐!

    start=(pagaNum-1) * pageSize

    第一步导入依赖

    1. <dependency>
    2. <groupId>com.github.pagehelpergroupId>
    3. <artifactId>pagehelperartifactId>
    4. <version>5.3.3version>
    5. dependency>

    第二步在核心配置文件设置插件:

    1. <plugins>
    2. <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    3. plugins>

    mapper接口:

    1. //分页插件查询所有
    2. List selectAll();

    mapper映射文件:

    1. <select id="selectAll" resultType="Car">
    2. select * from t_car
    3. select>

    这样看好像也没什么区别和之前的操作,是不是很迷惑!

    测试类来啦:

    1. //使用分页插件
    2. @Test
    3. public void test2(){
    4. SqlSession sqlSession = SqlSessionUtil.openSession();
    5. CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    6. //在执行DQL语句之前开启分页功能
    7. int pageNum=2;
    8. int pageSize=5;
    9. PageHelper.startPage(pageNum,pageSize);
    10. List carList = mapper.selectAll();
    11. carList.forEach(System.out::println);
    12. sqlSession.close();
    13. }

    另外说一下,pagehelper中可以将查询出来的数据封装到pageInfo中,然后这个对对象里面有很多的信息,真的就很牛 。节省很多功夫!这里有大概的数据展示可以了解一下!

    1. PageInfo{
    2. pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=6, pages=3,
    3. list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=6, pages=3, reasonable=false, pageSizeZero=false}
    4. [Car{id=86, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'},
    5. Car{id=87, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}],
    6. prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true,
    7. navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]
    8. }

    4、基于注解开发:

            mybatis中也提供了注解式开发方式,采用注解可以减少Sql映射文件的配置。但是使用注解式开发的话,sql语句是写在java程序中的,这种方式也会给sql语句的维护带来成本。

            使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

    注解方式插入数据:

    1. //注解方式插入
    2. @Insert(value="insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
    3. int insert(Car car);

    注解方式删除:

    1. @Delete("delete from t_car where id = #{id}")
    2. int deleteById(Long id);

    注解方式修改:

    1. @Update("update t_car set car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} where id=#{id}")
    2. int update(Car car);

    注解方式查询:

    1. @Select("select * from t_car where id = #{id}")
    2. @Results({
    3. @Result(column = "id", property = "id", id = true),
    4. @Result(column = "car_num", property = "carNum"),
    5. @Result(column = "brand", property = "brand"),
    6. @Result(column = "guide_price", property = "guidePrice"),
    7. @Result(column = "produce_time", property = "produceTime"),
    8. @Result(column = "car_type", property = "carType")
    9. })
    10. Car selectById(Long id);

    多个参数的注解方式:

    1. @Select("SELECT * FROM student WHERE name like '%${name}%' AND major like '%${major}%'")
    2. List find(@Param("name") String name, @Param("major") String major);

  • 相关阅读:
    关系代数与逻辑优化规则 (一): 定义
    组件之间通过bus中央事件总线进行通信
    Qt右键菜单
    ROS机械臂 Movelt 学习笔记2 | Move Group 接口 C++
    Flask 自建扩展
    记一次webpack迁移至vite【antd3(4)】
    y123.第七章 服务网格与治理-Istio从入门到精通 -- Sidecar及流量拦截机制(九)
    【今日文章】:Web端常用的Observer监听器
    9-ts抽象类
    青岛山水新城二期景观设计 全套设计
  • 原文地址:https://blog.csdn.net/keleID/article/details/133829260