一篇学会一级缓存 + ORM + 持久化

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

缓存作用

当对某些数据的查询请求频繁,且数据不经常修改时,使用缓存机制可以提高查询效率。

数据库发生commit操作时,缓存清空,防止一直查询缓存中的旧数据。

mybatis缓存执行流程

mybatis一级和二级缓存

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

mybatis一级缓存测试

  • mybatis默认开启一级缓存。

数据库未发生commit操作

测试代码

package com.example.mapper;

import com.example.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class TestUsersMapper {

//SqlSession对象
SqlSession sqlSession;

//mybatis动态代理对象
UsersMapper usersMapper;

//获取SqlSession
@Before
public void getSqlSession() throws IOException {
//读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//获取SqlSession
sqlSession = factory.openSession();
//获取mybatis动态代理对象
usersMapper = sqlSession.getMapper(UsersMapper.class);
}

//归还SqlSession
@After
public void closeSession(){
sqlSession.close();
}

//测试mybatis一级缓存
@Test
public void testOneLevelCache(){
//两次查询,id相同时
User u1 = usersMapper.getById(1);
System.out.println("第1次查询结果: " + u1);
System.out.println("----------------------");
User u2 = usersMapper.getById(1);
System.out.println("第2次查询结果: " + u2);
System.out.println("------------------------");
if(u1 == u2){
System.out.println("两个对象的内存地址相同");
}else{
System.out.println("两个对象的内存地址不同");
}
System.out.println("**************************************************");
//两次查询,id不同时
User u3 = usersMapper.getById(2);
System.out.println("第1次查询结果: " + u3);
System.out.println("----------------------");
User u4 = usersMapper.getById(5);
System.out.println("第2次查询结果: " + u4);
System.out.println("------------------------");
if(u3 == u4){
System.out.println("两个对象的内存地址相同");
}else{
System.out.println("两个对象的内存地址不同");
}
}
}

测试结果

==>  Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 1(Integer)
<== Columns: id, username, birthday, sex, address
<== Row: 1, 荷包蛋, 2002-08-23,, 黑河
<== Total: 1
第1次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
----------------------
第2次查询结果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
------------------------
两个对象的内存地址相同
**************************************************
==> Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 2(Integer)
<== Columns: id, username, birthday, sex, address
<== Row: 2, 小王, 2001-07-12, 1, 芜湖市
<== Total: 1
第1次查询结果: Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
----------------------
==> Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 5(Integer)
<== Columns: id, username, birthday, sex, address
<== Row: 5,, 2001-03-10, 1, 太原
<== Total: 1
第2次查询结果: Users{id=5, userName='段', birthday=Sat Mar 10 00:00:00 CST 2001, sex='1', address='太原'}
------------------------
两个对象的内存地址不同

结果分析

以上u1到u4同属于一个sqlSession域,因为下面代码只执行过一次,sqlSession只获取过一个,后面操作都是在该sqlSession对象的基础上进行的。

//获取SqlSession
sqlSession = factory.openSession();

当两次查询的id相同时,第一次查询开启了数据库连接,第二次没有再开启数据库连接,而是从缓存中获取,且两个对象内存地址相同其实u1和u2本质上是sqlSession域中的同一个对象。

当两次查询的id不同时,两次查询都开启了数据库连接,且两个对象内存地址不同其实u3和u4本质上是sqlSession域中的不同对象。

数据库发生commit操作时

测试代码

public void testOneLevelCache() throws ParseException {
//第1次查询,两次查询的id相同
User u1 = usersMapper.getById(1);
System.out.println("第1次查询结果: " + u1);
System.out.println("----------------------");

//中间发生commit操作
int num = usersMapper.insert(new User(8, "小涵", new SimpleDateFormat("yyyy-MM-dd").parse("2002-08-23"), "女", "黑河"));
if(num == 1){
System.out.println("数据插入成功!");
sqlSession.commit();
}else{
System.out.println("数据插入失败!");
}
System.out.println("---------------------------");
//第二次查询,与第一次查询的id相同
User u2 = usersMapper.getById(1);
System.out.println("第2次查询结果: " + u2);
System.out.println("------------------------");
if(u1 == u2){
System.out.println("两个对象的内存地址相同");
}else{
System.out.println("两个对象的内存地址不同");
}
}

测试结果

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

结果分析

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

注意

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

ORM

Object Relational Mapping:对象关系映射。

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

持久化

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

图示

责任编辑:武晓燕 来源: 今日头条
相关推荐

2009-09-22 13:09:06

Hibernateorm框架

2021-01-21 08:49:52

数据单体架构

2009-09-25 16:29:32

Hibernate一级

2009-09-24 15:42:44

Hibernate对象

2020-11-25 09:49:05

Hibernate

2009-09-23 17:03:08

Hibernate S

2009-09-28 11:12:52

2009-09-22 17:13:53

Hibernate O

2020-06-11 13:03:04

2009-06-18 14:51:12

Hibernate缓存Hibernate

2012-02-03 11:31:33

HibernateJava

2009-06-29 08:48:41

Hibernate缓存
点赞
收藏

51CTO技术栈公众号