日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatis框架:延迟加载策策略、一级缓存、二级缓存

發(fā)布時(shí)間:2024/10/8 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis框架:延迟加载策策略、一级缓存、二级缓存 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

MyBatis框架:延遲加載策略和緩存

  • Mybatis 延遲加載策略
    • 1.1 何為延遲加載?
    • 1.2 實(shí)現(xiàn)需求
    • 1.3 使用association實(shí)現(xiàn)延遲加載
      • 1.3.1 賬戶的持久層DAO接口
      • 1.3.2 賬戶的持久層映射文件
      • 1.3.3 用戶的持久層接口和映射文件
      • 1.3.4 開啟MyBatis的延遲加載策略
      • 1.3.5 編寫測試只查賬戶信息不查用戶信息
    • 1.4 使用Collection實(shí)現(xiàn)延遲加載
      • 1.4.1 在 User 實(shí)體類中加入 List屬性
      • 1.4.2 編寫用戶和賬戶持久層接口的方法
      • 1.4.3 編寫用戶持久層映射配置
      • 1.4.4 編寫賬戶持久層映射配置
      • 1.4.5 測試只加載用戶信息
  • Mybatis 緩存
    • 2.1 Mybatis 一級(jí)緩存
      • 2.1.1 證明一級(jí)緩存的存在
        • 2.1.1.1 編寫用戶持久層 Dao 接口
        • 2.1.1.2 編寫用戶持久層映射文件
        • 2.1.1.3 編寫測試方法
      • 2.1.2 一級(jí)緩存的分析
      • 2.1.3 測試一級(jí)緩存的清空
    • 2.2 Mybatis 二級(jí)緩存
      • 2.2.1 二級(jí)緩存結(jié)構(gòu)圖
      • 2.2.2 二級(jí)緩存的開啟與關(guān)閉
        • 2.2.2.1 第一步:在 SqlMapConfig.xml 文件開啟二級(jí)緩存
        • 2.2.2.2 第二步:配置相關(guān)的 Mapper 映射文件
        • 2.2.2.3 第三步:配置 statement 上面的 useCache 屬性
      • 2.2.3 二級(jí)緩存測試
      • 2.2.4 二級(jí)緩存注意事項(xiàng)

實(shí)際開發(fā)過程中很多時(shí)候我們并不需要總是在加載用戶信息時(shí)就一定要加載他的賬戶信息。此時(shí)就是我們所說的延遲加載。

Mybatis 延遲加載策略

1.1 何為延遲加載?

延遲加載:就是在需要用到數(shù)據(jù)時(shí)才進(jìn)行加載,不需要用到數(shù)據(jù)時(shí)就不加載數(shù)據(jù)。延遲加載也稱為懶加載。

好處:先從單表查詢,需要時(shí)再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度快。

壞處:因?yàn)橹挥挟?dāng)需要用到數(shù)據(jù)時(shí),才會(huì)進(jìn)行數(shù)據(jù)庫查詢,這樣在大批量數(shù)據(jù)查詢時(shí),因?yàn)椴樵児ぷ饕惨臅r(shí)間,所以可能造成用戶等待時(shí)間變長,造成用戶體驗(yàn)下降。

1.2 實(shí)現(xiàn)需求

需求:查詢賬戶(Account)信息并且關(guān)聯(lián)查詢用戶(User)信息。如果先查詢賬戶(Account)信息就可以滿足要求,當(dāng)需要查詢用戶(User)信息時(shí),再去查詢用戶(User)信息。把對(duì)用戶(User)信息的按需去查詢就是延遲加載。

主要是通過association、collection實(shí)現(xiàn)一對(duì)一和一對(duì)多映射,association、collection具備延遲加載功能。

1.3 使用association實(shí)現(xiàn)延遲加載

1.3.1 賬戶的持久層DAO接口

public interface IAccountDao { /** * 查詢所有賬戶,同時(shí)獲取賬戶的所屬用戶名稱以及它的地址信息 * @return */ List<Account> findAll(); }

1.3.2 賬戶的持久層映射文件

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IAccountDao"><!--定義封裝account和user的resultMap--><resultMap id="accountUserMap" type="account"><id property="id" column="id"/><result property="uid" column="uid"/><result property="money" column="money"/><!--一對(duì)一的關(guān)系映射:配置封裝user的內(nèi)容select屬性指定的內(nèi)容:查詢用戶的唯一標(biāo)識(shí)column屬性指定的內(nèi)容:用戶根據(jù)id查詢時(shí),所需要的參數(shù)的值--><association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"/></resultMap><!--查詢所有--><select id="findAll" resultMap="accountUserMap">select *from account</select> </mapper>

1.3.3 用戶的持久層接口和映射文件

package com.itheima.dao;import com.itheima.domain.User;import java.util.List;public interface IUserDao {User findById(Integer userId); } <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IUserDao"><select id="findById" parameterType="Integer" resultType="com.itheima.domain.User">select * from user where id = #{uid}</select> </mapper>

1.3.4 開啟MyBatis的延遲加載策略

<!--配置參數(shù)--><settings><!--開啟Mybatis支持延遲加載--><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/></settings>

1.3.5 編寫測試只查賬戶信息不查用戶信息

public class IAccountDaoTest {private InputStream in = null;private SqlSessionFactoryBuilder builder = null;private SqlSessionFactory factory = null;private SqlSession sqlSession = null;private IAccountDao accountDao = null;@Before //在測試方法執(zhí)行之前執(zhí)行public void setUp() throws Exception {//1.讀取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.創(chuàng)建構(gòu)建者對(duì)象builder = new SqlSessionFactoryBuilder();//3.創(chuàng)建 SqlSession 工廠對(duì)象factory = builder.build(in);sqlSession = factory.openSession();accountDao = sqlSession.getMapper(IAccountDao.class);}@Afterpublic void tearDown() throws Exception {sqlSession.commit();sqlSession.close();in.close();}@Testpublic void findAll() {List<Account> accounts = accountDao.findAll();for (Account account : accounts) {System.out.println(account); // System.out.println(account.getUser());}} }

測試結(jié)果如下:

我們發(fā)現(xiàn),因?yàn)楸敬沃皇菍?Account對(duì)象查詢出來放入 List 集合中,并沒有涉及到 User對(duì)象,所以就沒有發(fā)出 SQL 語句查詢賬戶所關(guān)聯(lián)的 User 對(duì)象的查詢。

1.4 使用Collection實(shí)現(xiàn)延遲加載

同樣我們也可以在一對(duì)多關(guān)系配置的<collection>結(jié)點(diǎn)中配置延遲加載策略。
<collection>結(jié)點(diǎn)中也有select屬性,column屬性。

需求:
完成加載用戶對(duì)象時(shí),查詢該用戶所擁有的賬戶信息。

1.4.1 在 User 實(shí)體類中加入 List屬性

public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;//一對(duì)多關(guān)系映射,主表實(shí)體應(yīng)該包含從表實(shí)體的集合引用private List<Account> accounts;}

1.4.2 編寫用戶和賬戶持久層接口的方法

package com.itheima.dao;import com.itheima.domain.User;import java.util.List;public interface IUserDao {List<User> findAll();User findById(Integer userId); } package com.itheima.dao;import com.itheima.domain.Account;import java.util.List;public interface IAccountDao {/*** 查詢所有賬戶,同時(shí)還要獲取當(dāng)前賬戶的所屬用戶信息** @return*/List<Account> findAll();/*** 根據(jù)用戶id查詢賬戶信息** @param uid* @return*/List<Account> findAccountByUid(Integer uid); }

1.4.3 編寫用戶持久層映射配置

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IUserDao"><!--定義User的resultMap信息--><resultMap id="userAccountMap" type="user"><id property="id" column="id"/><result property="username" column="username"/><result property="address" column="address"/><result property="sex" column="sex"/><result property="birthday" column="birthday"/><!--配置user對(duì)象中accounts集合的映射--><collection property="accounts" ofType="account"select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"/></resultMap><select id="findAll" resultMap="userAccountMap">select * from user u left outer join account a on u.id = a.uid</select><select id="findById" parameterType="Integer" resultType="com.itheima.domain.User">select * from user where id = #{uid}</select> </mapper>

1.4.4 編寫賬戶持久層映射配置

<!--根據(jù)用戶id查詢賬戶列表--><select id="findAccountByUid" resultType="account" parameterType="int">select * from account where uid=#{uid}</select>

1.4.5 測試只加載用戶信息

public class IUserDaoTest {private InputStream in = null;private SqlSessionFactoryBuilder builder = null;private SqlSessionFactory factory = null;private SqlSession sqlSession = null;private IUserDao userDao = null;@Beforepublic void setUp() throws Exception {in = Resources.getResourceAsStream("SqlMapConfig.xml");builder = new SqlSessionFactoryBuilder();factory = builder.build(in);sqlSession = factory.openSession();userDao = sqlSession.getMapper(IUserDao.class);}@Afterpublic void tearDown() throws Exception {sqlSession.commit();sqlSession.close();in.close();}@Testpublic void findAll() {List<User> userList = userDao.findAll();for (User user : userList) {System.out.println(user); // System.out.println(user.getAccounts());}} }

測試結(jié)果如下:我們發(fā)現(xiàn)并沒有加載 Account 賬戶信息。

Mybatis 緩存

像大多數(shù)的持久化框架一樣,Mybatis 也提供了緩存策略,通過緩存策略來減少數(shù)據(jù)庫的查詢次數(shù),從而提高性能。

Mybatis 中緩存分為一級(jí)緩存,二級(jí)緩存。

2.1 Mybatis 一級(jí)緩存

2.1.1 證明一級(jí)緩存的存在

一級(jí)緩存是 SqlSession 級(jí)別的緩存,只要 SqlSession 沒有 flush 或 close,它就存在。

2.1.1.1 編寫用戶持久層 Dao 接口

public interface IUserDao {User findById(Integer userId); }

2.1.1.2 編寫用戶持久層映射文件

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IUserDao"><select id="findById" parameterType="Integer" resultType="com.itheima.domain.User">select * from user where id = #{uid}</select> </mapper>

2.1.1.3 編寫測試方法

public class IUserDaoTest {private InputStream in = null;private SqlSessionFactoryBuilder builder = null;private SqlSessionFactory factory = null;private SqlSession sqlSession = null;private IUserDao userDao = null;@Beforepublic void setUp() throws Exception {in = Resources.getResourceAsStream("SqlMapConfig.xml");builder = new SqlSessionFactoryBuilder();factory = builder.build(in);sqlSession = factory.openSession();userDao = sqlSession.getMapper(IUserDao.class);}@Afterpublic void tearDown() throws Exception {sqlSession.commit();sqlSession.close();in.close();}@Testpublic void findAll() {List<User> userList = userDao.findAll();for (User user : userList) {System.out.println(user);}}/*** 測試一級(jí)緩存*/@Testpublic void testFirstLevelCache() {User u1 = userDao.findById(41);System.out.println(u1);User u2 = userDao.findById(41);System.out.println(u2);System.out.println(u1 == u2);//true} }

測試結(jié)果如下:

我們可以發(fā)現(xiàn),雖然在上面的代碼中我們查詢了兩次,但最后只執(zhí)行了一次數(shù)據(jù)庫操作,這就是 Mybatis 提供給我們的一級(jí)緩存在起作用了。因?yàn)橐患?jí)緩存的存在,導(dǎo)致第二次查詢 id 為 41 的記錄時(shí),并沒有發(fā)出 sql 語句從數(shù)據(jù)庫中查詢數(shù)據(jù),而是從一級(jí)緩存中查詢。

2.1.2 一級(jí)緩存的分析

一級(jí)緩存是 SqlSession 范圍的緩存,當(dāng)調(diào)用 SqlSession 的修改,添加,刪除,commit(),close()等方法時(shí),就會(huì)清空一級(jí)緩存。

第一次發(fā)起查詢用戶 id 為 1 的用戶信息,先去找緩存中是否有 id 為 1 的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。

得到用戶信息,將用戶信息存儲(chǔ)到一級(jí)緩存中。

如果 sqlSession 去執(zhí)行 commit 操作(執(zhí)行插入、更新、刪除),清空 SqlSession 中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。

第二次發(fā)起查詢用戶 id 為 1 的用戶信息,先去找緩存中是否有 id 為 1 的用戶信息,緩存中有,直接從緩存中獲取用戶信息。

2.1.3 測試一級(jí)緩存的清空

public class IUserDaoTest {private InputStream in = null;private SqlSessionFactoryBuilder builder = null;private SqlSessionFactory factory = null;private SqlSession sqlSession = null;private IUserDao userDao = null;@Beforepublic void setUp() throws Exception {in = Resources.getResourceAsStream("SqlMapConfig.xml");builder = new SqlSessionFactoryBuilder();factory = builder.build(in);sqlSession = factory.openSession();userDao = sqlSession.getMapper(IUserDao.class);}@Afterpublic void tearDown() throws Exception {sqlSession.commit();sqlSession.close();in.close();}/*** 測試一級(jí)緩存*/@Testpublic void testFirstLevelCache() {User u1 = userDao.findById(41);System.out.println(u1);User u2 = userDao.findById(41);System.out.println(u2);System.out.println(u1 == u2);//true}@Testpublic void testFirstLevelCache1() {User u1 = userDao.findById(41);System.out.println(u1);sqlSession.close();//再次獲取session對(duì)象sqlSession = factory.openSession();userDao = sqlSession.getMapper(IUserDao.class);User u2 = userDao.findById(41);System.out.println(u2);System.out.println(u1 == u2);//false}@Testpublic void testFirstLevelCache2() {User u1 = userDao.findById(41);System.out.println(u1);sqlSession.clearCache();User u2 = userDao.findById(41);System.out.println(u2);System.out.println(u1 == u2);//false}@Testpublic void testClearCache() {//1.根據(jù)id查詢用戶User user1 = userDao.findById(41);System.out.println(user1);//2.更新用戶信息user1.setUsername("update user clear cache");user1.setAddress("北京海淀");userDao.updateUser(user1);//3.再次查詢id為41的用戶User user2 = userDao.findById(41);System.out.println(user2);System.out.println(user1 == user2);} }

當(dāng)執(zhí)行sqlSession.close()后,再次獲取sqlSession并查詢id=41的User對(duì)象時(shí),又重新執(zhí)行了sql語句,從數(shù)據(jù)庫進(jìn)行了查詢操作。

2.2 Mybatis 二級(jí)緩存

二級(jí)緩存是 mapper 映射級(jí)別的緩存,多個(gè) SqlSession 去操作同一個(gè) Mapper 映射的 sql 語句,多個(gè) SqlSession 可以共用二級(jí)緩存,二級(jí)緩存是跨 SqlSession 的。

2.2.1 二級(jí)緩存結(jié)構(gòu)圖


首先開啟 mybatis 的二級(jí)緩存。

sqlSession1 去查詢用戶信息,查詢到用戶信息會(huì)將查詢數(shù)據(jù)存儲(chǔ)到二級(jí)緩存中。

如果 SqlSession3 去執(zhí)行相同 mapper 映射下 sql,執(zhí)行 commit 提交,將會(huì)清空該 mapper 映射下的二級(jí)緩存區(qū)域的數(shù)據(jù)。

sqlSession2 去查詢與 sqlSession1 相同的用戶信息,首先會(huì)去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。

2.2.2 二級(jí)緩存的開啟與關(guān)閉

2.2.2.1 第一步:在 SqlMapConfig.xml 文件開啟二級(jí)緩存

<!--配置參數(shù)--><settings><setting name="cacheEnabled" value="true"/></settings>

因?yàn)?cacheEnabled 的取值默認(rèn)就為 true,所以這一步可以省略不配置。為 true 代表開啟二級(jí)緩存;為 false 代表不開啟二級(jí)緩存。

2.2.2.2 第二步:配置相關(guān)的 Mapper 映射文件

標(biāo)簽表示當(dāng)前這個(gè) mapper 映射將使用二級(jí)緩存,區(qū)分的標(biāo)準(zhǔn)就看 mapper 的 namespace 值。

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.IUserDao"><!--開啟user支持二級(jí)緩存--><cache/> </mapper>

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

<select id="findById" parameterType="Integer" resultType="user" useCache="true">select *from userwhere id = #{uid}</select>

將 UserDao.xml 映射文件中的標(biāo)簽中設(shè)置 useCache=”true”代表當(dāng)前這個(gè) statement 要使用二級(jí)緩存,如果不使用二級(jí)緩存可以設(shè)置為 false。

注意:針對(duì)每次查詢都需要最新的數(shù)據(jù) sql,要設(shè)置成 useCache=false,禁用二級(jí)緩存。

2.2.3 二級(jí)緩存測試

public class secondLevelCacheTest {private InputStream in = null;private SqlSessionFactoryBuilder builder = null;private SqlSessionFactory factory = null;@Beforepublic void setUp() throws Exception {in = Resources.getResourceAsStream("SqlMapConfig.xml");builder = new SqlSessionFactoryBuilder();factory = builder.build(in);}@Afterpublic void tearDown() throws Exception {in.close();}/*** 測試一級(jí)緩存*/@Testpublic void testSecondLevelCache() {SqlSession sqlSession1 = factory.openSession();IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);User u1 = userDao1.findById(41);System.out.println(u1);sqlSession1.close();//一級(jí)緩存消失SqlSession sqlSession2 = factory.openSession();IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);User u2 = userDao2.findById(41);System.out.println(u2);sqlSession2.close();System.out.println(u1 == u2);//false} }

經(jīng)過上面的測試,我們發(fā)現(xiàn)執(zhí)行了兩次查詢,并且在執(zhí)行第一次查詢后,我們關(guān)閉了一級(jí)緩存,再去執(zhí)行第二次查詢時(shí),我們發(fā)現(xiàn)并沒有對(duì)數(shù)據(jù)庫發(fā)出 sql 語句,所以此時(shí)的數(shù)據(jù)就只能是來自于我們所說的二級(jí)緩存。

2.2.4 二級(jí)緩存注意事項(xiàng)

當(dāng)我們在使用二級(jí)緩存時(shí),所緩存的類一定要實(shí)現(xiàn) java.io.Serializable 接口,這種就可以使用序列化方式來保存對(duì)象。

public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address; }

總結(jié)

以上是生活随笔為你收集整理的MyBatis框架:延迟加载策策略、一级缓存、二级缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。