文章目录
1.Mybatis中的延迟加载
1.1延迟加载和立即加载
-
在用户和账户的关系中,假设此时我们有1个用户,该用户有100个账户。那么此时有这样一个问题。
- 当我们查询用户时,要不要把关联的账户也一起查询出来?
- 当我们查询账户时,要不要把关联的用户也一起查询出来?
-
显然当我们查询用户时,它的账户信息需要的时候再去查询,因为它有100个账户,如果全部查询出来非常的耗时,这就是所谓的
延迟加载
。而查询账户时,我们就可以同时把它对应的用户信息就查询出来,因为它只对应一个用户。这就是立即加载
。 -
延迟加载:
- 在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
- 在一对多或多对多的关系中通常采用延迟加载。
-
立即加载:
- 不管是否需要数据,只要一进行查询,就会把相关联的数据一并查询出来。
- 在多对一或一对一的关系中通常采用立即加载。
1.2一对一的延迟加载
- 需求:查询账户信息时,实现延迟加载,如果不需要用户信息,只查询账户信息。
- 账户的持久层映射文件:
<mapper namespace="com.zut.dao.IAccountDao">
<!-- 定义可以封装带有User的Account的 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" javaType="User" column="uid" select="com.zut.dao.IUserDao.getUserById"></association>
</resultMap>
<select id="findAll" resultMap="AccountUserMap">
SELECT * FROM account
</select>
</mapper>
- assocation标签中的select属性
表示我们要调用的映射语句的id
,它会从column属性指定的列中检索数据,作为参数传递给目标select语句
- column指定我们
要传递给select映射的参数
。
- 用户的持久层映射文件:
<mapper namespace="com.zut.dao.IUserDao">
<select id="getUserById" parameterType="java.lang.Integer" resultType="User">
select * from user where id=#{aa}
</select>
</mapper>
- 上面的都完成之后,我们需要在Mybatis的主配置文件中添加开启延迟加载的配置:
<!-- 开启延迟加载 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
- 注意在写setting标签时要写到正确的位置。具体参考Mybatis的官方文档:Mybatis的XML配置
- 测试结果如下:
- 我们发现只是将Account对象查询出来,而没有查询User对象。
1.3一对多实现延迟加载
- 需求:查询用户时实现延迟加载。
- 用户的持久层映射文件:
<mapper namespace="com.zut.dao.IUserDao">
<!-- 配置User的resultMap -->
<resultMap id="UserAccountMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="Account" select="com.zut.dao.IAccountDao.getAccountById" column="id"></collection>
</resultMap>
<select id="findAll" resultMap="UserAccountMap">
SELECT * from user
</select>
</mapper>
- 这里同样在collection标签中使用 select属性和column属性,作用和之前的一样。
- 账户的持久层映射文件:
<mapper namespace="com.zut.dao.IAccountDao">
<select id="getAccountById" parameterType="java.lang.Integer" resultType="account">
select * from account where uid = #{uid}
</select>
</mapper>
- 测试结果如下:
同样没有加载账户的信息。
2.Mybatis中的缓存
- 什么是缓存?
- 存在内存中的临时数据,
减少和数据库的交互次数
,提高执行效率。
- 存在内存中的临时数据,
- 什么样的数据能使用缓存,什么样的数据不能使用
- 适用于缓存:
- 经常查询并且不经常改变的
- 数据的正确与否对最终结果影响不大的
- 不适用于缓存:
- 经常改变的数据
- 数据的正确与否,对结果影响很大的
- 例如:商品的库存、银行的汇率、股市的牌价
- 适用于缓存:
2.1 Mybaits中的一级缓存
-
一级缓存:
- 它指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,
查询的结果会同时存入到SqlSession为我们提供的一块区域中
。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有
,有的话就直接拿出来用。当SqlSession对象消失时,Mybatis的一级缓存就消失了 - 一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就会存在。当调用 SqlSession 的修改、添加、删除、commit()、close()、clearCache() 等方法时,就会清空一级缓存。
- 它指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,
-
一级缓存的流程图如下:
- 第一次发起查询用户 id 为 1 的用户信息,Mybatis 会先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。
- 得到用户信息,将用户信息存储到一级缓存中。
- 如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),那么 Mybatis 就会清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读
- 第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息
- Mybatis中默认就是使用一级缓存的,不需要配置。
- 一级缓存中存放的是对象(其实就是Map结构)
2.2Mybatis中的二级缓存
-
它指的是Mybatis中的SqlSessionFactry对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存.
-
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
-
二级缓存的流程图如下:
意味同一个SqlSessionFactory创建的SqlSession可以共享二级缓存的内容
- 如果要使用二级缓存,需要做以下配置:
- 让Mybatis框架支持二级缓存,即在主配置文件中配置:
<settings>
<!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。
- 让当前的映射文件支持二级缓存,即在映射配置文件中配置:
<mapper namespace="cn.ykf.mapper.UserMapper">
<!-- 使用缓存 -->
<cache/>
</mapper>
- 让当前的操作支持二级缓存:
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>
将 UserDao.xml 映射文件中的select标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意:
- 当我们使用二级缓存的时候,
所缓存的类一定要实现 java.io.Serializable 接口
,这样才可以使用序列化的方式来保存对象。- 由于是序列化保存对象,所以
二级缓存中存放的是数据,而不是整个对象
。
3.Mybatis中的注解开发
3.1Mybatis的常用注解
注解 | 作用 |
---|---|
@Insert | 实现新增 |
@Update | 实现更新 |
@Delete | 实现删除 |
@Select | 实现查询 |
@Result | 实现结果集封装 |
@Results | 可以与@Result 一起使用,封装多个结果集 |
@ResultMap | 实现引用@Results 定义的封装 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
@SelectProvider | 实现动态 SQL 映射 |
@CacheNamespace | 实现注解二级缓存的使用 |
3.2使用Mybatis注解实现单表CRUD
- 用户实体类接口层的IUserDao的代码如下:
/**
* 在mybatis中,针对CRUD一共有四个注解
* @Select @Insert @Update @Delete
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
List<User> findAll();
/**
* 保存用户
* @param user
*/
@Insert("insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
/**
* 更新用户
* @param user
*/
@Update("update user set username=#{username},address=#{address},birthday=#{birthday},sex=#{sex} where id=#{id}")
void updateUser(User user);
/**
* 删除用户
* @param id
*/
@Delete("delete from user where id=#{aa}")
void deleteUser(Integer id);
}
上面的写法要求数据库里的列名和实体类中的属性一致,如果出现不一致的情况,要使用
@Result、@Results、@ResultMap
等标签。如下所示:
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday")
})
List<User> findAll();
3.3使用注解实现复杂关系映射的开发
实现复杂关系映射之前我们可以在映射文件中通过配置来实现,在使用注解开发时我们需要借
助@Results 注解,@Result 注解,@One 注解,@Many
注解。
-
@Results 注解:
代替的是标签resultMap
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result()) -
@Resutl 注解
代替了 id标签和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=""))
- select 指定用来多表查询的 sqlmapper
-
@Many 注解(多对一)
- 代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
- 代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。