MyBatis 基础知识四分析

虾米哥 阅读:182 2021-03-31 14:14:06 评论:0

第一:延迟加载策略

1.1 什么是延迟加载

延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载. 
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速 
度要快。 
 
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗 
时间,所以可能造成用户等待时间变长,造成用户体验下降。

1.2 延迟加载实现方式

1.2.1 使用 assocation 实现延迟加载

   <resultMap type="com.zzg.jdbc.mybatis.entity.Account" 
		id="accountExpand"> 
		<id property="id" column="id" /> 
		<result column="uid" property="uid" /> 
		<result column="name" property="name" /> 
		<result column="money" property="money" /> 
        <!-- 它是用于指定从表方的引用实体属性的 --> 
		<association property="user" column="uid" select="selectByPrimaryKeyExpandUser"/> 
	</resultMap> 
 
	<select id="selectByPrimaryKeyExpand"  resultMap="accountExpand"> 
		select a.* from account as a where a.id =1 
	</select> 
 
注意: 
    select: 填写我们要调用的 select 映射的 id  
    column : 填写我们要传递给 select 映射的参数

 1.2.2 使用 Collection 实现延迟加载

<resultMap type="user" id="userMap">  
    <id column="id" property="id"></id>  
    <result column="username" property="username"/> 
    <result column="address" property="address"/> 
    <result column="sex" property="sex"/> 
    <result column="birthday" property="birthday"/> 
    <!-- collection 是用于建立一对多中集合属性的对应关系 
    ofType 用于指定集合元素的数据类型 
    select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称) 
    column 是用于指定使用哪个字段的值作为条件查询 
    -->  
    <collection property="accounts" ofType="account" 
        select="com.itheima.dao.IAccountDao.findByUid" column="id"> 
    </collection> 
</resultMap> 
 
<!-- 配置查询所有操作 -->  
<select id="findAll" resultMap="userMap"> 
    select * from user 
</select> 
 
<collection>标签: 
主要用于加载关联的集合对象 
select 属性: 
用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 id 
column 属性: 
用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一 
个字段名了

第二:MyBatis 缓存

像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。
Mybatis 中缓存分为一级缓存,二级缓存。

2.1 一级缓存:一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。

2.1.1 一级缓存分析

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等
方法时,就会清空一级缓存。

第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查
询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样
做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存
中获取用户信息。

2.2 二级缓存

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

2.2.1 二级缓存结构图

首先开启 mybatis 的二级缓存。 
 
sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。 
 
如果 SqlSession3 去执行相同 mapper 映射下 sql,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据。 
 
sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

2.2.2 二级缓存开启流程 

第一步:在 SqlMapConfig.xml 文件开启二级缓存

<settings> 
<!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> 
</settings> 
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为 
false 代表不开启二级缓存

第二步:配置相关的 Mapper 映射文件

<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE mapper  
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IUserDao"> 
    <!-- 开启二级缓存的支持 --> 
    <cache></cache> 
</mapper>

第三步:配置 statement 上面的 useCache 属性

<!-- 根据 id 查询 --> <select id="findById" resultType="user" parameterType="int" useCache="true"> 
    select * from user where id = #{uid} 
</select> 将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用 
二级缓存,如果不使用二级缓存可以设置为 false。 
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

 

第三: MyBatis 注解

3.1 常用注解

@Insert:实现新增 
@Update:实现更新 
@Delete:实现删除 
@Select:实现查询 
@Result:实现结果集封装 
@Results:[email protected] 一起使用,封装多个结果集 
@ResultMap:[email protected] 定义的封装 
@One:实现一对一结果集封装 
@Many:实现一对多结果集封装 
@SelectProvider: 实现动态 SQL 映射 
@CacheNamespace:实现注解二级缓存的使用

3.2 基于注解实现增删改查

/** 
*  
* <p>Title: IUserDao</p> 
* <p>Description: 用户的持久层接口</p> 
* <p>Company: http://www.itheima.com/ </p> 
*/ 
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(); 
/* 
* 根据 id 查询一个用户 
* @param userId 
* @return 
*/ 
    @Select("select * from user where id = #{uid} ") 
    @ResultMap("userMap") 
    User findById(Integer userId); 
/** 
* 保存操作 
* @param user 
* @return 
*/ 
    @Insert("insert into  
        user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#       
         {address})") 
    @SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.class,before =  
        false, statement = { "select last_insert_id()" }) 
    int saveUser(User user); 
 
/** 
* 更新操作 
* @param user 
* @return 
*/ 
    @Update("update user set  
        username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id  
            =#{id} ") 
    int updateUser(User user); 
 
/** 
* 删除用户 
* @param userId 
* @return 
*/ 
    @Delete("delete from user where id = #{uid} ") 
    int deleteUser(Integer userId); 
 
/** 
* 查询使用聚合函数 
* @return 
*/ 
    @Select("select count(*) from user ") 
    int findTotal(); 
 
/** 
* 模糊查询 
* @param name 
* @return 
*/ 
    @Select("select * from user where username like #{username} ") 
        List<User> findByName(String name); 
    } 
通过注解方式,我们就不需要再去编写 UserDao.xml 映射文件了。

3.3 基于注解复杂关系映射

3.3.1 复杂关系注解说明:

@Results 注解 
代替的是标签<resultMap> 
[email protected] 注解,[email protected] 集合 
@Results([email protected](),@Result()})[email protected](@Result()) 
 
@Resutl 注解 
代替了 <id>标签和<result>标签 
@Result 中 属性介绍: 
    id 是否是主键字段 
    column 数据库的列名 
    property 需要装配的属性名 
    one [email protected] 注解(@Result([email protected])())) 
    many [email protected] 注解(@Result([email protected])())) 
 
@One 注解(一对一) 
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 
@One 注解属性介绍: 
    select 指定用来多表查询的 sqlmapper 
    fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。 
使用格式: 
@Result(column=" ",property="",[email protected](select="")) 
 
@Many 注解(多对一) 
代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。 
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType 
(一般为 ArrayList)但是注解中可以不定义; 
使用格式: 
@Result(property="",column="",[email protected](select=""))

3.3.2 基于注解实现一对一

/** 
*  
* <p>Title: IAccountDao</p> 
* <p>Description: 账户的持久层接口</p> 
* <p>Company: http://www.itheima.com/ </p> 
*/ 
public interface IAccountDao { 
    /** 
    * 查询所有账户,采用延迟加载的方式查询账户的所属用户 
    * @return 
    */ 
    @Select("select * from account") 
        @Results(id="accountMap", 
            value= { 
                @Result(id=true,column="id",property="id"), 
                @Result(column="uid",property="uid"), 
                @Result(column="money",property="money"), 
                @Result(column="uid",property="user", 
                    [email protected](select="com.itheima.dao.IUserDao.findById", 
                fetchType=FetchType.LAZY) ) 
   }) 
    List<Account> findAll(); 
}

3.3.3 基于注解实现一对多

/** 
* 
* <p>Title: IUserDao</p> 
* <p>Description: 用户的持久层接口</p> 
* <p>Company: http://www.itheima.com/ </p> 
*/ 
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"), 
            @Result(column="id",property="accounts", 
                   [email protected]( 
            select="com.itheima.dao.IAccountDao.findByUid", 
            fetchType=FetchType.LAZY) ) 
    }) 
    List<User> findAll(); 
} 
 
@Many: 
相当于<collection>的配置 
select 属性:代表将要执行的 sql 语句 
fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值

3.3.4 基于注解的二级缓存

在 SqlMapConfig 中开启二级缓存支持

<!-- 配置二级缓存 -->  
<settings> 
    <!-- 开启二级缓存的支持 -->  
    <setting name="cacheEnabled" value="true"/> 
</settings>

在持久层接口中使用注解配置二级缓存

/** 
*  
* <p>Title: IUserDao</p> 
* <p>Description: 用户的持久层接口</p> 
* <p>Company: http://www.itheima.com/ </p> 
*/ 
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存 
public interface IUserDao {}

 

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
排行榜
关注我们

一个IT知识分享的公众号