Mybatis学习日志四
学习目标
- 能够使用mybatis的延迟加载
- 能够使用mybatis的一级缓存二级缓存
- 能够掌握mybatis中的注解开发
1 Mybatis中的延迟加载
问题:在一对多中,当我们有一个用户,他有100个账户。
- 在查询用户的时候,要不要把关联的账户查出来?
- 不需要,什么时候使用,什么时候再查询。
- 在查询账户的时候,要不要把关联的用户查出来?
- 需要,查询账户时用户信息需一同查询出来。
1.1 延迟加载
在真正使用数据时才发起查询,不用的时候不查询。(懒加载)
1.1.1 使用Assocation实现延迟加载(一对一)
select属性:
- 查询用户的唯一标识
- 写法为:主表的映射文件namespace.方法名
column属性:
- 在之前可以不写,但是延迟加载时必须写
- 用户根据id查询时,所需要的参数的值
<!-- 定义封装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>
<!-- 一对一的映射关系,配置封装user -->
<association property="user" column="uid" javaType="user" select="dao.IUserDao.findById"></association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account;
</select>
上述配置一一配置好,并不能实现延迟加载的功能
在mybatis中延迟加载的全局开关默认值为false
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。描述 | true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 | true | false | false (在 3.4.1 及之前的版本中默认为 true) |
所以我们需要在主配置文件中配置参数
<!-- 配置参数 -->
<settings>
<!-- 开启全局支持延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
1.1.2 使用Collection实现延迟加载(一对多)
与1.1.1配置一样。
- 在Account中创建一个方法,通过用户id查询账户
/**
* 通过用户id查询账户
* @return
*/
List<User> findAccountByUid();
-
IAccount配置
<!-- 通过用户ID查询账户 --> <select id="findAccountByUid" resultType="user"> select * from account where uid = #{uid}; </select>
-
IUserDao配置
<!-- 定义封装account和user的resultMap --> <resultMap id="allUserAccountMap" 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> <!-- 一对一的映射关系,配置封装account --> <collection property="accounts" ofType="account" select="dao.IAccountDao.findAccountByUid" column="id"></collection> </resultMap> <!-- 查询用户的同时查询其账户的所有信息 --> <select id="findAll" resultMap="allUserAccountMap"> select * from user; </select>
1.2 立即加载
不管用不用,只要一调用方法,马上发起查询。(饿加载)
在对应的四种表关系中:
一对多,多对多:通常情况下采用延迟加载。
多对一,一对一:通常情况下采用立即加载。
2 Mybatis中的缓存
什么是缓存:
- 存在于内存中的临时数据。
为什么使用缓存:
- 减少和数据库的交互次数,提高执行效率。
数据使用缓存的情况:
-
适用于缓存:
- 经常查询
- 不经常改变
- 数据的正确与否对最终结果影响不大的。
-
不适用于缓存:
- 经常改变的数据
- 数据的正确与否对最终结果影响很大的。
2.1 一级缓存
它指的是Mybatis中的SQLSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
sqlSession.clearCache();
可以清空缓存
注:一级缓存是SqlSession范围的缓存,当调用SqlSession的CUD、commit()、close()等方法时,就会清空一级缓存。
2.2 二级缓存
它指的是Mybatis中SqlSessionFactory对象的缓存。
由同一个SqlSessionFactory对象创建的SqlSession对象共享一块缓存。
二级缓存的使用步骤:
-
让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
设置名 描述 有效值 默认值 cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true -
让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<cache/>
-
让当前的方法支持二级缓存(在select标签中配置)
<!-- 查询用户 -->
<select id="findById" parameterType="Integer" resultType="user" useCache="true">
select * from user where id=#{uid}
</select>
注:二级缓存中存放的内容是数据,而不是对象。当再次查询时,将会把这些数据封装起来重新创建一个对象并返回。
3 Mybatis中的注解开发
在注解开发中,如果使用了注解并且又存在接口对应的配置文件,那么不管使用mapper中的class还是resource属性都会报错
3.1 单表CRUD操作(代理Dao模式)
在mybatis中针对CRUD共有4个注解
@Select,@Insert,@Update,@Delete
3.2 解决实体类与数据库名称不对应问题
当实体类中的属性名与数据库中的属性名不同时,我们需要注解配置。
@Results(String id,Result[] value)
- id:此配置唯一标识
- value:Result配置
- Result:boolean id是否为主键,property实体类中的名称,column对应的数据库列表名。
@Results(id = "userMap",value = {
@Result(id = true,property = "userId",column = "id"),
@Result(property = "userName",column = "username"),
@Result(property = "userAddress",column = "address"),
@Result(property = "userSex",column = "sex"),
@Result(property = "userBirthday",column = "birthday"),
})
配置好Results之后,如果其他方法需要用到,则使用@ResultMap(String[] value) -->@ResultMap(value = {“userMap”}
3.3 多表查询操作
3.3.1 多对一(Mybatis中的一对一)
-
创建账户实体类
-
在账户实体类中创建用户的映射(一个账户只能属于一个用户)
-
在账户持久层中创建方法
/** * 查询所有账户并获取每个账户所属的用户信息 * @return */ @Select("select * from account") @Results(value = { @Result(id = true,column = "id",property = "id"), @Result(column = "uid",property = "uid"), @Result(column = "money",property = "money"), @Result(property = "user",column = "uid",one = @One(select = "dao.IUserDao.findById",fetchType = FetchType.EAGER)) }) List<Account> findAll();
3.3.2 一对多
-
在用户实体类中创建账户集合的映射(一个用户可以拥有多个账户)
-
在账户接口中创建,通过uid查询账户的方法
/** * 通过uid查询账户 * @param uid * @return */ @Select("select * from account where uid=#{uid}") List<Account> findByUid(Integer uid);
-
在用户的持久层创建对应方法
/** * 查询所有用户并查询出对应的账户信息 * @return */ @Select("select * from user") @Results(value = { @Result(id = true,column = "id",property = "id"), @Result(column = "username",property = "username"), @Result(column = "address",property = "address"), @Result(column = "sex",property = "sex"), @Result(column = "birthday",property = "birthday"), @Result(property = "accounts",column = "id",many=@Many(select = "dao.IAccountDao.findByUid",fetchType = FetchType.LAZY)) }) List<User> findAll();
3.4 缓存的配置
一级缓存自动开启
在需要使用二级缓存的持久层接口名上添加
@CacheNamespace(blocking = true)//就可以使用二级缓存了
@CacheNamespace(blocking = true)
public interface IUserDao {
****
****
****
}
untDao.findByUid",fetchType = FetchType.LAZY))
})
List<User> findAll();
3.4 缓存的配置
一级缓存自动开启
在需要使用二级缓存的持久层接口名上添加
@CacheNamespace(blocking = true)//就可以使用二级缓存了
@CacheNamespace(blocking = true)
public interface IUserDao {
****
****
****
}