文章目录
1.Mybatis中的延迟加载1.1延迟加载和立即加载1.2一对一的延迟加载1.3一对多实现延迟加载
2.Mybatis中的缓存2.1 Mybaits中的一级缓存2.2Mybatis中的二级缓存
3.Mybatis中的注解开发3.1Mybatis的常用注解3.2使用Mybatis注解实现单表CRUD3.3使用注解实现复杂关系映射的开发
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() 等方法时,就会清空一级缓存。
一级缓存的流程图如下:
第一次发起查询用户 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的代码如下:
public interface IUserDao {
@Select("select * from user")
List
<User> findAll();
@Insert("insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user
);
@Update("update user set username=#{username},address=#{address},birthday=#{birthday},sex=#{sex} where id=#{id}")
void updateUser(User user
);
@Delete("delete from user where id=#{aa}")
void deleteUser(Integer id
);
}
上面的写法要求数据库里的列名和实体类中的属性一致,如果出现不一致的情况,要使用@Result、@Results、@ResultMap等标签。如下所示:
public interface IUserDao {
@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=""))
@Many 注解(多对一)
代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。 注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义; 使用格式: @Result(property="",column="",many=@Many(select=""))