版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
数据准备
首先我们创建两张表:
CREATE TABLE `person` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
`name` varchar(45) NOT NULL DEFAULT '' COMMENT '姓名',
`gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '性别(1:男,2:女)',
`company_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '公司id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '人员信息表';
CREATE TABLE `company` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar(45) NOT NULL DEFAULT '' COMMENT '公司名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='公司信息表';
接下来我们往两张表中插入一些数据:
INSERT INTO person (age, name, gender, company_id) VALUES (1, 'tia', 1, 1);
INSERT INTO company (name) VALUES ('A');
实体和DAO准备
环境的搭建这里不过多赘述了,相信大家都能很轻松的搞定。
实体
/**
* 实体基类
*/
@Data
public class BaseModel implements Serializable {
public static final long serialVersionUID = 1L;
private Date modified;
private Date created;
private Long id;
}
@Data
@ToString(callSuper = true)
public class Person extends BaseModel {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 性别
*/
private Byte gender;
/**
* 公司id
*/
private Long companyId;
/**
* 公司信息
*/
private Company company;
}
@Data
@ToString(callSuper = true)
public class Company extends BaseModel {
/**
* 姓名
*/
private String name;
}
DAO
/**
* @author 0xZzzz
*/
@CacheNamespace
public interface PersonDAO {
/**
* 主键查询
*
* @param id pk
* @return person
*/
@Select("select * from person where id = #{id}")
Person getById(Long id);
/**
* 关联company
*
* @param id pk
* @return person join company
*/
@Select("select t1.*, t2.id as company_id, t2.id as \"company.id\", t2.name as \"company.name\" "
+ "from person t1 left join company t2 on t1.company_id = t2.id "
+ "where t1.id = #{id}")
Person joinCompanyById(Long id);
/**
* 更新
*
* @param person row
* @return effect rows
*/
@Update("update person set name = #{name} where id = #{id}")
int update(Person person);
}
@CacheNamespace
public interface CompanyDAO {
/**
* 主键查询
*
* @param id pk
* @return row
*/
@Select("select * from company where id = #{id}")
Company getById(Long id);
/**
* 更新
*
* @param company row
* @return effect rows
*/
@Update("update company set name = #{name} where id = #{id}")
int update(Company company);
}
一级缓存测试
测试思路
因为一级缓存是SqlSession维度的缓存,所以我们创建两个SqlSession对象,都读取数据库的同一条记录,然后用其中一个SqlSession对象改变这条记录的值,然后用另一个SqlSession对象再次读取这条记录,看是否会读取到过期的值。
代码实现
public String level1() {
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
PersonDAO personDAO1 = sqlSession1.getMapper(PersonDAO.class);
Person person1 = personDAO1.getById(1L);
System.err.println("sqlSession1 query:" + person1);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
PersonDAO personDAO2 = sqlSession2.getMapper(PersonDAO.class);
System.err.println("sqlSession2 query:" + personDAO2.getById(1L));
person1.setName("lia");
personDAO1.update(person1);
System.err.println("sqlSession1 update:" + personDAO1.getById(1L));
System.err.println("sqlSession2 query: " + personDAO2.getById(1L));
return "OK";
}
解释一下方法的流程:
- 首先我们创建SqlSession对象sqlSession1,并用其读取person表中id为1的记录并打印
- 然后我们创建另一个SqlSession对象sqlSession2,同样用其读取person表中id为1的记录并打印
- 接下来我们用sqlSession1将这条记录的name字段更新为lia,再次查询并打印
- 最后我们用sqlSession2再次查询这条记录并查看结果
结果输出
sqlSession1 query:Person(super=BaseModel(modified=null, created=null, id=1), name=tia, age=22, gender=1, companyId=1, company=null)
sqlSession2 query:Person(super=BaseModel(modified=null, created=null, id=1), name=tia, age=22, gender=1, companyId=1, company=null)
sqlSession1 update:Person(super=BaseModel(modified=null, created=null, id=1), name=lia, age=22, gender=1, companyId=1, company=null)
sqlSession2 query: Person(super=BaseModel(modified=null, created=null, id=1), name=tia, age=22, gender=1, companyId=1, company=null)
我们看到,在sqlSession1将name字段修改lia之后,sqlSession2再次读取这条记录读到的还是tia,所以在使用Mybatis一级缓存的时候确实会存在缓存不一致的问题,使用时我们需要注意这个点。
二级缓存测试
测试思路
因为MyBatis二级缓存是namespace维度的缓存,所以我们把针对同一张表的CRUD操作定义在两个不同的namespace也就是DAO中,用其中的一个DAO更新掉这张表一条记录,然后用另一个DAO再次查询这条记录,看是否会读取到过期的值。
代码实现
public String level2() {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
CompanyDAO companyDAO = sqlSession.getMapper(CompanyDAO.class);
Company company = companyDAO.getById(1L);
sqlSession.commit();
System.err.println("CompanyDAO query company:" + company);
PersonDAO personDAO = sqlSession.getMapper(PersonDAO.class);
Person person = personDAO.joinCompanyById(1L);
sqlSession.commit();
System.err.println("PersonDAO query person join company:" + person);
company.setName("B");
companyDAO.update(company);
sqlSession.commit();
System.err.println("CompanyDAO update company:" + companyDAO.getById(1L));
System.err.println("PersonDAO query person join company:" + personDAO.joinCompanyById(1L));
sqlSession.commit();
return "OK";
}
解释一下方法的流程:
- 首先我们用CompanyDAO读取company表中id为1的记录并打印
- 然后我们用PersonDAO读取person表中id为1的记录,并关联company表中id为1的记录,读取后打印
- 接下来我们用CompanyDAO将company表中id为1的记录的name字段更新为B,再次查询并打印
- 最后我们用PersonDAO再次查询关联后的记录并查看结果
结果输出
CompanyDAO query company:Company(super=BaseModel(modified=null, created=null, id=1), name=A)
PersonDAO query person join company:Person(super=BaseModel(modified=null, created=null, id=1), name=lia, age=22, gender=1, companyId=1, company=Company(super=BaseModel(modified=null, created=null, id=1), name=A))
CompanyDAO update company:Company(super=BaseModel(modified=null, created=null, id=1), name=B)
PersonDAO query person join company:Person(super=BaseModel(modified=null, created=null, id=1), name=lia, age=22, gender=1, companyId=1, company=Company(super=BaseModel(modified=null, created=null, id=1), name=A))
我们看到在CompanyDAO将company表中id为1的记录的name字段修改为B后,PersonDAO再次查询关联的记录后,Company的name还是A,所以在使用Mybatis二级缓存的时候也确实会存在缓存不一致的问题,使用时我们需要注意这个点。