資料準備
首先我們建立兩張表:
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二級緩存的時候也确實會存在緩存不一緻的問題,使用時我們需要注意這個點。