• 一级缓存 + ORM + 持久化


    缓存作用

    • 当对某些数据的查询请求频繁,且数据不经常修改时,使用缓存机制可以提高查询效率
    • 数据库发生commit操作时,缓存清空,防止一直查询缓存中的旧数据

    mybatis缓存执行流程

     mybatis一级和二级缓存

     

    • 一级缓存作用域:sqlSession对象
    • 二级缓存作用域:Mapper.xml文件
    • 查询顺序:先二级缓存,再一级缓存,最后查数据库

    mybatis一级缓存测试

    • mybatis默认开启一级缓存

    数据库未发生commit操作

    测试代码

    1. package com.example.mapper;
    2. import com.example.pojo.User;
    3. import org.apache.ibatis.io.Resources;
    4. import org.apache.ibatis.session.SqlSession;
    5. import org.apache.ibatis.session.SqlSessionFactory;
    6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    7. import org.junit.After;
    8. import org.junit.Before;
    9. import org.junit.Test;
    10. import java.io.IOException;
    11. import java.io.InputStream;
    12. public class TestUsersMapper {
    13. //SqlSession对象
    14. SqlSession sqlSession;
    15. //mybatis动态代理对象
    16. UsersMapper usersMapper;
    17. //获取SqlSession
    18. @Before
    19. public void getSqlSession() throws IOException {
    20. //读取核心配置文件
    21. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    22. //创建SqlSessionFactory对象
    23. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    24. //获取SqlSession
    25. sqlSession = factory.openSession();
    26. //获取mybatis动态代理对象
    27. usersMapper = sqlSession.getMapper(UsersMapper.class);
    28. }
    29. //归还SqlSession
    30. @After
    31. public void closeSession(){
    32. sqlSession.close();
    33. }
    34. //测试mybatis一级缓存
    35. @Test
    36. public void testOneLevelCache(){
    37. //两次查询,id相同时
    38. User u1 = usersMapper.getById(1);
    39. System.out.println("第1次查询结果: " + u1);
    40. System.out.println("----------------------");
    41. User u2 = usersMapper.getById(1);
    42. System.out.println("第2次查询结果: " + u2);
    43. System.out.println("------------------------");
    44. if(u1 == u2){
    45. System.out.println("两个对象的内存地址相同");
    46. }else{
    47. System.out.println("两个对象的内存地址不同");
    48. }
    49. System.out.println("**************************************************");
    50. //两次查询,id不同时
    51. User u3 = usersMapper.getById(2);
    52. System.out.println("第1次查询结果: " + u3);
    53. System.out.println("----------------------");
    54. User u4 = usersMapper.getById(5);
    55. System.out.println("第2次查询结果: " + u4);
    56. System.out.println("------------------------");
    57. if(u3 == u4){
    58. System.out.println("两个对象的内存地址相同");
    59. }else{
    60. System.out.println("两个对象的内存地址不同");
    61. }
    62. }
    63. }

    测试结果

    1. ==> Preparing: select id, username, birthday, sex, address from users where id=?
    2. ==> Parameters: 1(Integer)
    3. <== Columns: id, username, birthday, sex, address
    4. <== Row: 1, 荷包蛋, 2002-08-23, 女, 黑河
    5. <== Total: 1
    6. 1次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
    7. ----------------------
    8. 2次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
    9. ------------------------
    10. 两个对象的内存地址相同
    11. **************************************************
    12. ==> Preparing: select id, username, birthday, sex, address from users where id=?
    13. ==> Parameters: 2(Integer)
    14. <== Columns: id, username, birthday, sex, address
    15. <== Row: 2, 小王, 2001-07-12, 1, 芜湖市
    16. <== Total: 1
    17. 1次查询结果: Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
    18. ----------------------
    19. ==> Preparing: select id, username, birthday, sex, address from users where id=?
    20. ==> Parameters: 5(Integer)
    21. <== Columns: id, username, birthday, sex, address
    22. <== Row: 5, 段, 2001-03-10, 1, 太原
    23. <== Total: 1
    24. 2次查询结果: Users{id=5, userName='段', birthday=Sat Mar 10 00:00:00 CST 2001, sex='1', address='太原'}
    25. ------------------------
    26. 两个对象的内存地址不同

    结果分析

    • 以上u1到u4同属于一个sqlSession域,因为下面代码只执行过一次,sqlSession只获取过一个,后面操作都是在该sqlSession对象的基础上进行的
    1. //获取SqlSession
    2. sqlSession = factory.openSession();
    • 当两次查询的id相同时,第一次查询开启了数据库连接,第二次没有再开启数据库连接,而是从缓存中获取,且两个对象内存地址相同其实u1和u2本质上是sqlSession域中的同一个对象
    • 当两次查询的id不同时,两次查询都开启了数据库连接,且两个对象内存地址不同其实u3和u4本质上是sqlSession域中的不同对象

    数据库发生commit操作时

    测试代码

    1. public void testOneLevelCache() throws ParseException {
    2. //1次查询,两次查询的id相同
    3. User u1 = usersMapper.getById(1);
    4. System.out.println("第1次查询结果: " + u1);
    5. System.out.println("----------------------");
    6. //中间发生commit操作
    7. int num = usersMapper.insert(new User(8, "小涵", new SimpleDateFormat("yyyy-MM-dd").parse("2002-08-23"), "女", "黑河"));
    8. if(num == 1){
    9. System.out.println("数据插入成功!");
    10. sqlSession.commit();
    11. }else{
    12. System.out.println("数据插入失败!");
    13. }
    14. System.out.println("---------------------------");
    15. //第二次查询,与第一次查询的id相同
    16. User u2 = usersMapper.getById(1);
    17. System.out.println("第2次查询结果: " + u2);
    18. System.out.println("------------------------");
    19. if(u1 == u2){
    20. System.out.println("两个对象的内存地址相同");
    21. }else{
    22. System.out.println("两个对象的内存地址不同");
    23. }
    24. }

    测试结果

    1. ==> Preparing: select id, username, birthday, sex, address from users where id=?
    2. ==> Parameters: 1(Integer)
    3. <== Columns: id, username, birthday, sex, address
    4. <== Row: 1, 荷包蛋, 2002-08-23, 女, 黑河
    5. <== Total: 1
    6. 1次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
    7. ----------------------
    8. ==> Preparing: insert into users(username, birthday, sex, address) values(?, ?, ?, ?)
    9. ==> Parameters: 小涵(String), 2002-08-23 00:00:00.0(Timestamp), 女(String), 黑河(String)
    10. <== Updates: 1
    11. 数据插入成功!
    12. Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c18016b]
    13. ---------------------------
    14. ==> Preparing: select id, username, birthday, sex, address from users where id=?
    15. ==> Parameters: 1(Integer)
    16. <== Columns: id, username, birthday, sex, address
    17. <== Row: 1, 荷包蛋, 2002-08-23, 女, 黑河
    18. <== Total: 1
    19. 2次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
    20. ------------------------
    21. 两个对象的内存地址不同

    结果分析

    • 数据库发生commit操作时,缓存被清空,两次查询虽然id相同,但是第二次在缓存中查不到数据,只能重新获取数据库连接

    注意

    • mybatis框架是优秀的ORM框架,专注于sql查询,数据映射
    • 缓存问题应该交给专门负责缓存的其他第三方框架

    ORM

    • Object Relational Mapping:对象关系映射
    • java语言中以对象方式操作数据,在数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射

    持久化

    • 将数据保存到关系型数据库中,将关系型数据库中的数据读取出来以对象的形式封装,整个过程称为持久化

    图示

     

  • 相关阅读:
    vue3中的reactive赋值问题
    反转链表(力扣)
    arduino(esp8266)驱动74hc595进行流水灯异常一例
    TiFlash 源码阅读(五) DeltaTree 存储引擎设计及实现分析 - Part 2
    猎聘爬虫(附源码)
    css技巧分享(优惠券缺角样式实现)
    2022适合3D渲染的电脑配置清单来了,如何选电脑?
    基础设施SIG月度动态:「龙蜥大讲堂」基础设施系列专题分享完美收官,容器镜像构建 2.0 版本上线
    瑞吉外卖(优化篇)
    使用NTP配置集群时间同步(CentOS 7.9操作系统)
  • 原文地址:https://blog.csdn.net/Cr1556648487/article/details/126557700