mybatis之脏数据产生与避免
一、脏数据产生
<mapper namespace="com.example.simple.mapper.UserMapper"> <cache eviction="FIFO" flushInterval="6000" size="512" readOnly="false"/> </mapper>
<mapper namespace="com.example.simple.mapper.RoleMapper"> <cache eviction="FIFO" flushInterval="6000" size="512" readOnly="false"/> </mapper>
SysRole.java和SysUser.java序列化实现:
public class SysUser implements Serializable { private static final long serialVersionUID = 6320941908222932112L ; }
public class SysRole implements Serializable { private static final long serialVersionUID = 6320941908222932112L ; }
2. 准备代码测试:
@Test public void testDirtyDate(){ SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser user = userMapper.selectUserAndRoleById(1001L); Assert.assertEquals("普通用户",user.getRole().getRoleName()); System.out.println("角色名:" + user.getRole().getRoleName()); }finally { sqlSession.close(); } System.out.println("开启一个新的session"); sqlSession = getSqlSession(); try{ RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); SysRole role = roleMapper.selectById(2L); role.setRoleName("脏数据"); //提交修改 sqlSession.commit(); }finally { sqlSession.close(); } System.out.println("开启第二个新的session"); sqlSession = getSqlSession(); try{ UserMapper userMapper = sqlSession.getMapper(UserMapper.class); RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); SysUser user = userMapper.selectUserAndRoleById(1001L); SysRole role = roleMapper.selectById(2l); Assert.assertEquals("普通用户" , user.getRole().getRoleName()); Assert.assertEquals("脏数据" , role.getRoleName());; System.out.println("角色名:" + user.getRole().getRoleName()); //还原数据 role.setRoleName("普通用户"); roleMapper.updateById(role); sqlSession.commit(); }finally { sqlSession.close(); } }
测试后结果:
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.UserMapper]: 0.0
DEBUG [main] - ==> Preparing: select u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail , u.user_info userInfo , u.head_img headImg, u.create_time createTime , r.id "role.id", r.role_name "role.roleName" , r.enabled "role.enabled" , r.create_by "role.createBy", r.create_time "role.createTime" from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id where u.id = ?
DEBUG [main] - ==> Parameters: 1001(Long)
TRACE [main] - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime, role.id, role.roleName, role.enabled, role.createBy, role.createTime
TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.com, <<BLOB>>, <<BLOB>>, 2020-12-01 20:05:01, 2, 普通用户, 1, 1, 2020-12-01 20:05:04
DEBUG [main] - <== Total: 1
角色名:普通用户
开启一个新的session
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.0
DEBUG [main] - ==> Preparing: select id, role_name,enabled,create_by,create_time from sys_role where id = ?
DEBUG [main] - ==> Parameters: 2(Long)
TRACE [main] - <== Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <== Row: 2, 普通用户, 1, 1, 2020-12-01 20:05:04
DEBUG [main] - <== Total: 1
开启第二个新的session
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.UserMapper]: 0.5
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.5
角色名:普通用户
DEBUG [main] - ==> Preparing: update sys_role set enabled = ? where id = ?
DEBUG [main] - ==> Parameters: 1(Integer), 2(Long)
DEBUG [main] - <== Updates: 1
测试的思路和脏数据产生分析是:
第一个sqlSession负责先关联用户表和角色表将user_id = 1001L的用户信息和角色信息查询出来;
第二个sqlSession负责将上一个sqlSession中查询到的角色信息对应的role_id进行再查询,并对role_name进行赋值,使得role_name被赋予新值;
第三个sqlSession分别通过SysUser类和SysRole类获取角色name,发现两者取出来的值并不一样,这时就出现了脏数据,这时因为UserMapper.xml和RoleMapper.xml中分别设置的二级缓存互不影响,这时就出现了同一角色对应两个name。
二、脏数据避免
脏数据产生原因是二级缓存在不同的mapper.xml中,因此出现了缓存内容不一样,内容显示不一致的原因,这时解决方案如下:
<mapper namespace="com.example.simple.mapper.UserMapper"> <cache-ref namespace="com.example.simple.mapper.RoleMapper"/> <!-- <cache eviction="FIFO" flushInterval="6000" size="512" readOnly="false"/>--> </mapper>
这时测试结果是:
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.0
DEBUG [main] - ==> Preparing: select u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail , u.user_info userInfo , u.head_img headImg, u.create_time createTime , r.id "role.id", r.role_name "role.roleName" , r.enabled "role.enabled" , r.create_by "role.createBy", r.create_time "role.createTime" from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id where u.id = ?
DEBUG [main] - ==> Parameters: 1001(Long)
TRACE [main] - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime, role.id, role.roleName, role.enabled, role.createBy, role.createTime
TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.com, <<BLOB>>, <<BLOB>>, 2020-12-01 20:05:01, 2, 普通用户, 1, 1, 2020-12-01 20:05:04
DEBUG [main] - <== Total: 1
角色名:普通用户
开启一个新的session
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.0
DEBUG [main] - ==> Preparing: select id, role_name,enabled,create_by,create_time from sys_role where id = ?
DEBUG [main] - ==> Parameters: 2(Long)
TRACE [main] - <== Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <== Row: 2, 普通用户, 1, 1, 2020-12-01 20:05:04
DEBUG [main] - <== Total: 1
开启第二个新的session
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.3333333333333333
DEBUG [main] - Cache Hit Ratio [com.example.simple.mapper.RoleMapper]: 0.5
角色名:普通用户
DEBUG [main] - ==> Preparing: update sys_role set enabled = ? where id = ?
DEBUG [main] - ==> Parameters: 1(Integer), 2(Long)
DEBUG [main] - <== Updates: 1
这样一来,二级缓存就存在于两个关联表中,因此就实现了脏数据的避免。