MyBatis缓存不一致问题测试

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/heroqiang/article/details/85339834

数据准备

首先我们创建两张表:

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";
}

解释一下方法的流程:

  1. 首先我们创建SqlSession对象sqlSession1,并用其读取person表中id为1的记录并打印
  2. 然后我们创建另一个SqlSession对象sqlSession2,同样用其读取person表中id为1的记录并打印
  3. 接下来我们用sqlSession1将这条记录的name字段更新为lia,再次查询并打印
  4. 最后我们用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";
}

解释一下方法的流程:

  1. 首先我们用CompanyDAO读取company表中id为1的记录并打印
  2. 然后我们用PersonDAO读取person表中id为1的记录,并关联company表中id为1的记录,读取后打印
  3. 接下来我们用CompanyDAO将company表中id为1的记录的name字段更新为B,再次查询并打印
  4. 最后我们用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二级缓存的时候也确实会存在缓存不一致的问题,使用时我们需要注意这个点。

猜你喜欢

转载自blog.csdn.net/heroqiang/article/details/85339834