MyBatis延迟加载策略
延迟加载的定义
- 延迟加载: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
- 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
- 坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
实现需求
- 需求: 查询账户(Account)信息并且关联查询用户(User)信息。如果先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。把对用户(User)信息的按需去查询就是延迟加载。
- 在03实现多表操作时,我们使用了resultMap来实现一对一,一对多,多对多关系的操作。主要是通过association、collection实现一对一及一对多映射。association、collection具备延迟加载功能。
项目结构
1 | ─src |
使用assocation实现延迟加载
账户持久层DAO接口的查询方法
1
2
3
4
5/**
* 查询所有账户,同时还要获取到当前账户的所属用户信息
* @return
*/
List<Account> findAll();
账户的持久层映射文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<mapper namespace="wzc.dao.IAccountDao">
<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 配置延迟加载
select属性指定的内容:查询用户的唯一标识:
column属性指定的内容:用户根据id查询时,所需要的参数的值
-->
<association property="user" column="uid" javaType="user" select="wzc.dao.IUserDao.findById"></association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
SELECT * FROM account
</select>
</mapper>- select: 填写我们要调用的 select 映射的 id
- column : 填写我们要传递给 select 映射的参数
用户的持久层DAO接口的查询方法
1
2
3
4
5
6/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);用户的持久层映射文件
1
2
3
4
5
6
7
8
9
10
<mapper namespace="wzc.dao.IUserDao">
<!-- 根据id查询用户 -->
<select id="findById" parameterType="int" resultType="user">
SELECT * FROM user WHERE id = #{uid};
</select>
</mapper>
SqlMapConfig.xml中开启Mybatis的延迟加载策略
1
2
3
4
5
6<!-- 配置参数 -->
<settings>
<!-- 开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
测试只查账户信息不查用户信息的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public class AccountTest {
private InputStream in;
private SqlSession sqlSession;
private IAccountDao accountDao;
//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取dao的代理对象
accountDao = sqlSession.getMapper(IAccountDao.class);
}
//用于在测试方法执行之后执行
public void destroy() throws Exception {
//要手动提交事务(autocommit默认为false)
sqlSession.commit();
//6.释放资源
sqlSession.close();
in.close();
}
/**
* 测试查询所有
*/
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
}
}
使用Collection实现延迟加载
- 同样我们也可以在一对多关系配置的
结点中配置延迟加载策略。 结点中也有select属性,column属性。 - 需求: 完成加载用户对象时,查询该用户所拥有的账户信息。
在User实体类中加入List
属性 1
2
3
4
5
6
7
8
9
10//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
用户持久层DAO接口方法
1
2
3
4
5/**
* 查询所有用户,同时获取到用户下所有账户的信息
* @return
*/
List<User> findAll();
账户持久层DAO接口方法
1
2
3
4
5
6/**
* 根据用户id查询账户信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
用户持久层映射配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 定义User的ResultMap -->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account" select="wzc.dao.IAccountDao.findAccountByUid" column="id">
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
SELECT * FROM user
</select>标签: 主要用于加载关联的集合对象 - select属性: 用于指定查询account列表的sql语句,所以填写的是该sql映射的id
- column属性: 用于指定select属性的sql语句的参数来源,上面的参数来自于user的id列,所以就写成id这一个字段名了
账户持久层映射配置
1
2
3
4<!-- 根据用户id查询账户列表 -->
<select id="findAccountByUid" resultType="account">
SELECT * FROM account WHERE uid = #{uid}
</select>
测试只加载用户信息的方法
1
2
3
4
public void testFindAll(){
List<User> users = userDao.findAll();
}
MyBatis缓存
像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。
Mybatis中缓存分为一级缓存,二级缓存。

项目结构
1 | ─src |
MyBatis一级缓存
- 证明一级缓存的存在
一级缓存是SqlSession级别的缓存,只要SqlSession没有flush或close,它就存在。
用户持久层DAO接口的方法
1
2
3
4
5
6/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);
用户持久层映射文件
1
2
3
4
5
6
7
8
9
10
<mapper namespace="wzc.dao.IUserDao">
<!-- 根据id查询用户 -->
<select id="findById" parameterType="int" resultType="user" useCache="true">
SELECT * FROM user WHERE id = #{uid};
</select>
</mapper>
测试方法
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 测试一级缓存
*/
public void testFirstLevelCache(){
User user1 = userDao.findById(41);
System.out.println("第一次查询的用户:" + user1);
User user2 = userDao.findById(41);
System.out.println("第二次查询的用户:" + user2);
System.out.println(user1 == user2);
}- 测试结果: true. 对数据库进行了一次查询
- 分析: 虽然在上面的代码中我们查询了两次,但最后只执行了一次数据库操作,这就是Mybatis提供给我们的一级缓存在起作用了。因为一级缓存的存在,导致第二次查询id为41的记录时,并没有发出sql语句从数据库中查询数据,而是从一级缓存中查询。
一级缓存的分析
- 一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
- 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
- 得到用户信息,将用户信息存储到一级缓存中。
- 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
- 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
测试一级缓存的清空
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void testFirstLevelCache(){
User user1 = userDao.findById(41);
System.out.println(user1);
// sqlSession.close();
//再次获取SqlSession对象
// sqlSession = factory.openSession();
sqlSession.clearCache();//此方法也可以清空缓存
//再次获取dao代理对象
userDao = sqlSession.getMapper(IUserDao.class);
User user2 = userDao.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);
}- 测试结果: false. 对数据库进行了两次查询
- 当执行sqlSession.close()后,再次获取sqlSession并查询id=41的User对象时,又重新执行了sql 语句,从数据库第二次进行了查询操作。
MyBatis二级缓存
- 二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
- 二级缓存结构
- 首先开启mybatis的二级缓存。
- sqlSession1去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。
- 如果SqlSession3去执行相同 mapper映射下sql,执行commit提交,将会清空该 mapper映射下的二级缓存区域的数据。
sqlSession2去查询与sqlSession1相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
第一步:在SqlMapConfig.xml文件开启二级缓存
1
2
3<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:配置相关的Mapper映射文件
1
2
3
4<mapper namespace="wzc.dao.IUserDao">
<!-- 开启user支持二级缓存 -->
<cache/>
</mapper>标签表示当前这个mapper映射将使用二级缓存,区分的标准就看mapper的namespace值。
第三步:配置statement上面的useCache属性
1
2
3
4<!-- 根据id查询用户 -->
<select id="findById" parameterType="int" resultType="user" useCache="true">
SELECT * FROM user WHERE id = #{uid};
</select>将映射文件中的select标签中设置useCache=”true”代表当前这个statement要使用二级缓存,如果不使用二级缓存可以设置为false。
- 注意:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
二级缓存测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40public class SecondLevelCacheTest {
private InputStream in;
private SqlSessionFactory factory;
//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
}
//用于在测试方法执行之后执行
public void destroy() throws Exception {
in.close();
}
/**
* 测试一级缓存
*/
public void testFirstLevelCache(){
SqlSession sqlSession1 = factory.openSession();
IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = dao1.findById(41);
System.out.println(user1);
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession();
IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = dao2.findById(41);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1 == user2);
}
}- 测试结果: false. 且只对数据库进行了一次查询
- 执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出sql语句,所以此时的数据就只能是来自于二级缓存。
二级缓存注意事项
- 当我们在使用二级缓存时,所缓存的类一定要实现java.io.Serializable接口,这种就可以使用序列化方式来保存对象。
MyBatis注解开发
- 这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。
MyBatis的常用注解说明
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与
- @Result一起使用,封装多个结果集
- @ResultMap:实现引用
- @Results定义的封装
- @One:实现一对一结果集封装
- @Many:实现一对多结果集封装
- @SelectProvider: 实现动态SQL映射
- @CacheNamespace:实现注解二级缓存的使用
项目结构
1 | ─src |
使用MyBatis注解实现基本CRUD
实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
public Integer getUserId() { return userId; }
public void setUserId(Integer userId) { this.userId = userId; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public Date getUserBirthday() { return userBirthday; }
public void setUserBirthday(Date userBirthday) { this.userBirthday = userBirthday; }
public String getUserSex() { return userSex;}
public void setUserSex(String userSex) { this.userSex = userSex; }
public String getUserAddress() { return userAddress; }
public void setUserAddress(String userAddress) { this.userAddress = userAddress; }
public String toString() {
return "User [userId=" + userId + ", userName=" + userName + ", userBirthday=" + userBirthday + ", userSex=" + userSex + ", userAddress=" + userAddress + "]";
}
}- 注意: 此处故意和数据库表的列名不一致。
使用注解方式开发持久层DAO接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62public interface IUserDao {
/**
* 查询所有用户
* @return
*/
"SELECT * FROM user") (
"userMap", (id=
value={
true,column="id",property="userId"), (id=
"username",property="userName"), (column=
"sex",property="userSex"), (column=
"address",property="userAddress"), (column=
"birthday",property="userBirthday") (column=
})
List<User> findAll();
/**
* 保存用户
* @param user
*/
"INSERT INTO user(username, address, sex, birthday) VALUES (#{username},#{address},#{sex},#{birthday})") (
void saveUser(User user);
/**
* 更新用户
* @param user
*/
"UPDATE user SET username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} WHERE id=#{id}") (
void updateUser(User user);
/**
* 删除用户
* @param userId
*/
"DELETE FROM user WHERE id=#{id}") (
void deleteUser(Integer userId);
/**
* 根据id查询用户
* @param userId
* @return
*/
"SELECT * FROM user WHERE id=#{id}") (
User findById(Integer userId);
/**
* 根据用户名模糊查询
* @param username
* @return
*/
// @Select("SELECT * FROM user WHERE username LIKE #{username}")
"SELECT * FROM user WHERE username LIKE '%${value}%'") (
List<User> findUserByName(String username);
/**
* 查询总用户数量
* @return
*/
"SELECT COUNT(*) FROM user") (
int findTotalUser();
}- 通过注解方式,就不需要再去编写UserDao.xml 映射文件了。
SqlMapConfig 配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<configuration>
<!-- 引入外部配置文件 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置别名 -->
<typeAliases>
<package name="wzc.domain"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 指定带有注解的dao接口所在位置 -->
<mappers>
<package name="wzc.dao"></package>
</mappers>
</configuration>
测试方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
public void init() throws Exception {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
userDao = session.getMapper(IUserDao.class);
}
public void destroy() throws Exception {
session.commit();
session.close();
in.close();
}
public void testSave(){
User user = new User();
user.setUsername("mybatis annotation");
user.setAddress("南京市鼓楼区");
userDao.saveUser(user);
}
public void testUpdate(){
User user = new User();
user.setId(56);
user.setUsername("mybatis annotation update");
user.setAddress("南京市鼓楼区");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}
public void testDelete(){
userDao.deleteUser(54);
}
public void testFindOne(){
User user = userDao.findById(56);
System.out.println(user);
}
public void testFindByName(){
// List<User> users = userDao.findUserByName("%mybatis%");//占位符 SELECT * FROM user WHERE username LIKE ?
List<User> users = userDao.findUserByName("mybatis");//字符串拼接方式 SELECT * FROM user WHERE username LIKE '%mybatis%'
for (User user : users) {
System.out.println(user);
}
}
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
}
使用注解实现复杂关系映射开发
- 实现复杂关系映射之前我们可以在映射文件中通过配置
来实现,在使用注解开发时我们需要借助@Results注解,@Result注解,@One注解,@Many注解。
项目结构
1 | ─src |
复杂关系映射的注解说明
@Results注解
代替的是标签
该注解中可以使用单个@Result注解,也可以使用@Result集合
@Results({@Result(),@Result()})或@Results(@Result())
@Result注解
代替了
标签和 标签 @Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property需要装配的属性名
one 需要使用的@One注解(@Result(one=@One)()))
many 需要使用的@Many注解(@Result(many=@many)()))
@One注解(一对一)
代替了
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 @One注解属性介绍:
select 指定用来多表查询的sqlmapper
fetchType会覆盖全局的配置参数lazyLoadingEnabled。
使用格式: @Result(column=” “,property=””,one=@One(select=””))
@Many注解(多对一) 代替了
标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。 注意:聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList)但是注解中可以不定义;
使用格式: @Result(property=””,column=””,many=@Many(select=””))
使用注解实现一对一复杂关系映射及延迟加载
User实体类及Account实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115/**
* 用户实体类
*/
public class User implements Serializable{
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public Date getUserBirthday() {
return userBirthday;
}
public void setUserBirthday(Date userBirthday) {
this.userBirthday = userBirthday;
}
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAddress='" + userAddress + '\'' +
", userSex='" + userSex + '\'' +
", userBirthday=" + userBirthday +
'}';
}
}
/**
* 账户实体类
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
账户的持久层DAO接口并使用注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public interface IAccountDao {
/**
* 查询所有账户,并且获取每个账户所属的用户信息
* 注意:多对一@Result用@One注解,fetchType = FetchType.EAGER
* 一对多@Result用@Many注解,fetchType = FetchType.LAZY
* @return
*/
"SELECT * FROM account") (
"accountMap", value = { (id =
true,column = "id",property = "id"),//id=true表示该列为主键 (id =
"uid",property = "uid"), (column =
"money",property = "money"), (column =
"user", (property =
column = "uid",
one = "wzc.dao.IUserDao.findById",fetchType = FetchType.EAGER)), (select =
})
List<Account> findAll();
}
用户的持久层DAO接口并使用注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public interface IUserDao {
/**
* 查询所有用户
* @return
*/
"SELECT * FROM user") (
"userMap", value = { (id =
true,column = "id",property = "userId"), (id =
"username",property = "userName"), (column =
"address",property = "userAddress"), (column =
"sex",property = "userSex"), (column =
"birthday",property = "userBirthday") (column =
})
List<User> findAll();
/**
* 根据id查询用户
* @param userId
* @return
*/
"SELECT * FROM user WHERE id=#{id}") (
// @ResultMap(value = {"userMap"})//只有一个属性value可省略,数组中只有一个元素{}也可省略
"userMap") (
User findById(Integer userId);
}
测试一对一关联及延迟加载
1
2
3
4
5
6
7
8
9
public void testFindAll(){
List<Account> accounts = acountDao.findAll();
/*for (Account account : accounts) {
System.out.println("----------每个账户的信息-----------");
System.out.println(account);
System.out.println(account.getUser());
}*/
}
- 使用注解实现一对多复杂关系映射
- 需求: 查询用户信息时,也要查询他的账户列表。使用注解方式实现。
- 分析: 一个用户具有多个账户信息,所以形成了用户(User)与账户(Account)之间的一对多关系。
User实体类中加入List
1
2
3
4
5
6
7
8
9
10//一对多关系映射:一个用户对应多个账户
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
用户的持久层DAO接口并使用注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public interface IUserDao {
/**
* 查询所有用户
* @return
*/
"SELECT * FROM user") (
"userMap", value = { (id =
true,column = "id",property = "userId"), (id =
"username",property = "userName"), (column =
"address",property = "userAddress"), (column =
"sex",property = "userSex"), (column =
"birthday",property = "userBirthday"), (column =
"accounts",column = "id", (property =
many = "wzc.dao.IAccountDao.findAccountByUid", (select =
fetchType = FetchType.LAZY))
})
List<User> findAll();
}- @Many: 相当于
的配置 - select属性:代表将要执行的sql语句
- fetchType属性:代表加载方式,一般如果要延迟加载都设置为LAZY的值
- @Many: 相当于
账户的持久层DAO接口并使用注解配置
1
2
3
4
5
6
7
8
9public interface IAccountDao {
/**
* 根据用户id查询账户信息
* @param userId
* @return
*/
"SELECT * FROM account WHERE uid = #{userId}") (
List<Account> findAccountByUid(Integer userId);
}
测试方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
public void init() throws Exception {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
userDao = session.getMapper(IUserDao.class);
}
public void destroy() throws Exception {
session.commit();
session.close();
in.close();
}
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println("------每个用户的信息--------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
}
MyBatis基于注解的二级缓存
在SqlMapConfig中开启二级缓存支持
1
2
3
4<!-- 配置开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在持久层DAO接口中使用注解配置二级缓存
1
2
3
4true)//mybatis基于注解方式实现配置二级缓存 (blocking =
public interface IUserDao {
...
}