学习mybatis的第四天

1.Mybatis 延迟加载策略

问题:在一对多中,当我们有一个用户,该用户有100个账户,

①在查询用户的时候,要不要把关联的账户查询出来?

②在查询账户的时候,要不要把关联的用户信息查询出来?

解决方案是:

①在查询用户的时候,用户下的账户信息应该是什么时候使用,什么时候查询。(延迟加载)

②在查询账户的时候,账户下的所属用户信息应该是随账户一起查询出来。(立即加载)

1.1什么为延迟加载:

延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。按需加载,延迟加载也称懒加载.

好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗

时间,所以可能造成用户等待时间变长,造成用户体验下降。

*注意:

一对一、多对一通常情况下采用立即加载

多对多、一对多通常情况下采用延迟加载

1.2用延迟加载实现需求:

需求:

查询账户(Account)信息并且关联查询用户(User)信息。如果先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。把对用户(User)信息的按需去查询就是延迟加载。

mybatis第三天实现多表操作时,使用了resultMap来实现一对一,一对多,多对多关系的操作。主要是通过 association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。

在全局的xml文件SqlMapConfig文件中配置:

<settings>

<setting name="lazyLoadingEnabled" value="true"/>

<setting name="aggressiveLazyLoading" value="false"/>

</settings>

①使用association完成延迟加载:

需求:

查询账户信息同时查询用户信息(在多对一即mybatis中的一对一的情况下完成延迟加载)

IAccountDao接口中的方法:

public interface IAccountDao {

/*** 查询所有账户,同时获取账户的所属用户名称以及它的地址信息

* @return

*/

List<Account> findAll( );

}

IAccoutDao.xml映射文件的配置:

<!-- 建立对应关系 -->

<mapper  namespace = "com.itheima.dao.IAccountDao">

<resultMap type="account" id="accountMap">

<id column="aid" property="id"/>

<result column="uid" property="uid"/>

<result column="money" property="money"/>

<!-- 它是用于指定从表方的引用实体属性的 -->

<association property="user"  javaType="user"

select="com.itheima.dao.IUserDao.findById"  column="uid">

</association>

</resultMap>

<select id="findAll" resultMap="accountMap">

    select * from account

</select>

</mapper>

select : 填写我们要调用的 select 映射的 id,即在IUserDao接口中的findById的方法

column : 填写我们要传递给 select 映射的参数,传给findById方法的参数,在这里肯定为account表中的uid

IUserDao接口中的方法:

public interface IUserDao {

/**

* 根据 id 查询

* @param userId*

@return

*/

User findById(Integer id);

}   

IUserDao.xml映射文件的配置:

<mapper namespace="com.itheima.dao.IUserDao">

<!-- 根据 id 查询 -->

<select id="findById" resultType="user" parameterType="int" >

select * from user where id = #{uid}

</select>

</mapper>

②使用collection完成延迟加载:

需求:

完成加载用户对象时,查询该用户所拥有的账户信息(在一对多的情况下完成延迟加载)

IUserDao接口中的方法:

/**

*查询所有用户,同时获取出每个用户下的所有账户信息

* @return

*/

List<User> findAll(  );

IUserDao.xml文件的配置:

<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 这一个字段名了

IAccountDao接口中的方法:

/**

* 根据用户 id 查询账户信息

* @param uid

* @return

*/

List<Account>   findByUid(Integer uid); 

IAccountDao.xml配置文件:

<!-- 根据用户 id 查询账户信息 -->

<select id="findByUid"  resultType="account"   parameterType="int">

        select * from account where uid = #{uid}

</select>

2.Mybatis中的缓存机制

       像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提

高性能。

        Mybatis 中缓存分为一级缓存,二级缓存。

什么是缓存:存在于内存中的临时数据;

为什么使用缓存:减少和数据库交换的次数,提高执行效率;

适用于缓存的数据:经常查询的数据并且不经常改变,数据的正确与否对最终的结果影响不大的;

不适用于缓存的数据:经常改变的数据,数据的正确与否对最终的结果影响很大的;

2.1Mybatis中的一级缓存:

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

原理:当我们执行查询之后,查询结果会存入到SqlSession对象为我们提供的一块区域中。该区域的结构是一个Map,当我们再次查询相同的数据时,mybatis会先去SqlSession中查询是否有,有的话直接拿出来使用。当SqlSession对象消失时,mybatis的一级缓存也就消失了。

一级缓存的分析:

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


分析图

        第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查

询用户信息。

        得到用户信息,将用户信息存储到一级缓存中。

        如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样

做的目的为了让缓存中存储的是最新的信息,避免脏读。

        第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存

中获取用户信息。

2.2Mybatis中的二级缓存:

     二级缓存:存放的内容是数据(JSON格式),而不是对象,会创建新对象,进行存改;    

     二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。指的是mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

二级缓存结构图

        首先开启 mybatis 的二级缓存。

        sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

        如果 SqlSession3 去执行相同 mapper 映射下 sql,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据。

        sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从

缓存中取出数据。

        使用步骤:

         ①让mybatis框架支持二级缓存,在全局配置文件中配置:

<settings>

<setting name = "cacheEnable"  value ="true"/>

</settings>

        ②让当前映射文件支持二级缓存,配置:

  <mapper namespace="com.itheima.dao.IUserDao">

<!-- 开启二级缓存的支持 -->

<cache></cache>

</mapper>

      ③让当前的操作支持二级缓存,在select标签中配置:

<!-- 根据 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,禁用二级缓存。

二级缓存注意事项:当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。

3.Mybatis中的注解开发:

3.1 mybatis 的常用注解说明:

@Insert:实现新增

@Update:实现更新

@Delete:实现删除

@Select:实现查询

@Result:实现结果集封装

@Results:可以与@Result 一起使用,封装多个结果集

@ResultMap:实现引用@Results 定义的封装

@One:实现一对一结果集封装

@Many:实现一对多结果集封装

@SelectProvider: 实现动态 SQL 映射

@CacheNamespace:实现注解二级缓存的使用

注解开发测试使用的注意事项:

采用注解开发时,在全局配置文件中配置:

<mappers>

<mapper class = "com.itheima.dao.IUserDao"/>

</mappers>

或者直接配置:

<mappers>

        <package name="com.itheima.dao"/>

</mappers>

*注意:采用注解开发时,不能在同一个文件名称下dao进行xml开发,即使使用resource属性也不能。

如:dao接口在com.itheima.dao下,而对应接口的映射配置文件xml也在resources的com.itehima.dao目录下,此时就会报错,要么把xml移到别的目录,然后删除整个目录文件,要么直接删除文件和文件目录。

3.2使用注解实现复杂关系映射开发:

        实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,在使用注解开发时我们需要借

助@Results 注解,@Result 注解,@One 注解,@Many 注解。

        复杂关系映射的注解说明:

@Results 注解   代替的是标签<resultMap>

@Resutl 注解    代替了 <id> 标签和<result> 标签

@Result 中 属性介绍:

        id 是否是主键字段

        column 数据库的列名

        property 需要装配的属性名

        one 需要使用的@One 注解(@Result(one=@One)()))

        many 需要使用的@Many 注解(@Result(many=@many)()))

@one中的属性介绍:  

       @One 注解(一对一) 代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

        select   指定用来多表查询的 sqlmapper

        fetchType 会覆盖全局的配置参数 FetchType.LAZY(延迟加载)或者FetchType.EAGER(立即加载)

例如:

IAccountDao

*注意:

此时最后一个@Result注解中,column属性指定用来多表查询的sqlmapper的参数  ,

@Many 注解(多对一)

        代替了<Collection> 标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。

注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;

例如:

IUserDao

3.3 mybatis 基于注解的二级缓存:

①.在全局配置文件SqlMapConfig.xml中配置开启二级缓存:

<!-- 配置二级缓存 -->

<settings>

    <!-- 开启二级缓存的支持 -->

    <setting name="cacheEnabled" value="true"/>

</settings>

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

@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容