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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

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

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

Mybatis 延遲加載策略

1.1 何為延遲加載?

延遲加載:就是在需要用到數據時才進行加載,不需要用到數據時就不加載數據。延遲加載也稱為懶加載。

好處:先從單表查詢,需要時再從關聯表去關聯查詢,大大提高數據庫性能,因為查詢單表要比關聯查詢多張表速度快。

壞處:因為只有當需要用到數據時,才會進行數據庫查詢,這樣在大批量數據查詢時,因為查詢工作也要消耗時間,所以可能造成用戶等待時間變長,造成用戶體驗下降。

1.2 實現需求

需求:查詢賬戶(Account)信息并且關聯查詢用戶(User)信息。如果先查詢賬戶(Account)信息就可以滿足要求,當需要查詢用戶(User)信息時,再去查詢用戶(User)信息。把對用戶(User)信息的按需去查詢就是延遲加載。

主要是通過association、collection實現一對一和一對多映射,association、collection具備延遲加載功能。

1.3 使用association實現延遲加載

1.3.1 賬戶的持久層DAO接口

public interface IAccountDao { /** * 查詢所有賬戶,同時獲取賬戶的所屬用戶名稱以及它的地址信息 * @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"/><!--一對一的關系映射:配置封裝user的內容select屬性指定的內容:查詢用戶的唯一標識column屬性指定的內容:用戶根據id查詢時,所需要的參數的值--><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的延遲加載策略

<!--配置參數--><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 //在測試方法執行之前執行public void setUp() throws Exception {//1.讀取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.創建構建者對象builder = new SqlSessionFactoryBuilder();//3.創建 SqlSession 工廠對象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());}} }

測試結果如下:

我們發現,因為本次只是將 Account對象查詢出來放入 List 集合中,并沒有涉及到 User對象,所以就沒有發出 SQL 語句查詢賬戶所關聯的 User 對象的查詢。

1.4 使用Collection實現延遲加載

同樣我們也可以在一對多關系配置的<collection>結點中配置延遲加載策略。
<collection>結點中也有select屬性,column屬性。

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

1.4.1 在 User 實體類中加入 List屬性

public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;//一對多關系映射,主表實體應該包含從表實體的集合引用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 {/*** 查詢所有賬戶,同時還要獲取當前賬戶的所屬用戶信息** @return*/List<Account> findAll();/*** 根據用戶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對象中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 編寫賬戶持久層映射配置

<!--根據用戶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());}} }

測試結果如下:我們發現并沒有加載 Account 賬戶信息。

Mybatis 緩存

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

Mybatis 中緩存分為一級緩存,二級緩存。

2.1 Mybatis 一級緩存

2.1.1 證明一級緩存的存在

一級緩存是 SqlSession 級別的緩存,只要 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);}}/*** 測試一級緩存*/@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} }

測試結果如下:

我們可以發現,雖然在上面的代碼中我們查詢了兩次,但最后只執行了一次數據庫操作,這就是 Mybatis 提供給我們的一級緩存在起作用了。因為一級緩存的存在,導致第二次查詢 id 為 41 的記錄時,并沒有發出 sql 語句從數據庫中查詢數據,而是從一級緩存中查詢。

2.1.2 一級緩存的分析

一級緩存是 SqlSession 范圍的緩存,當調用 SqlSession 的修改,添加,刪除,commit(),close()等方法時,就會清空一級緩存。

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

得到用戶信息,將用戶信息存儲到一級緩存中。

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

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

2.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 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對象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.根據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);} }

當執行sqlSession.close()后,再次獲取sqlSession并查詢id=41的User對象時,又重新執行了sql語句,從數據庫進行了查詢操作。

2.2 Mybatis 二級緩存

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

2.2.1 二級緩存結構圖


首先開啟 mybatis 的二級緩存。

sqlSession1 去查詢用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。

如果 SqlSession3 去執行相同 mapper 映射下 sql,執行 commit 提交,將會清空該 mapper 映射下的二級緩存區域的數據。

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

2.2.2 二級緩存的開啟與關閉

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

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

因為 cacheEnabled 的取值默認就為 true,所以這一步可以省略不配置。為 true 代表開啟二級緩存;為 false 代表不開啟二級緩存。

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

標簽表示當前這個 mapper 映射將使用二級緩存,區分的標準就看 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支持二級緩存--><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 映射文件中的標簽中設置 useCache=”true”代表當前這個 statement 要使用二級緩存,如果不使用二級緩存可以設置為 false。

注意:針對每次查詢都需要最新的數據 sql,要設置成 useCache=false,禁用二級緩存。

2.2.3 二級緩存測試

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();}/*** 測試一級緩存*/@Testpublic void testSecondLevelCache() {SqlSession sqlSession1 = factory.openSession();IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);User u1 = userDao1.findById(41);System.out.println(u1);sqlSession1.close();//一級緩存消失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} }

經過上面的測試,我們發現執行了兩次查詢,并且在執行第一次查詢后,我們關閉了一級緩存,再去執行第二次查詢時,我們發現并沒有對數據庫發出 sql 語句,所以此時的數據就只能是來自于我們所說的二級緩存。

2.2.4 二級緩存注意事項

當我們在使用二級緩存時,所緩存的類一定要實現 java.io.Serializable 接口,這種就可以使用序列化方式來保存對象。

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天操精品 | 成人性生生活性生交全黄 | 秋霞午夜鲁丝一区二区老狼 | 青草福利在线 | 日韩精品一区二区不卡 | 美女被爆操网站 | 九九这里只有精品视频 | 97国产成人 | 国产永久在线观看 | 一区二区三区久久久久 | 女女同性女同一区二区三区按摩 | 国产综合久久 | 免费av导航| 国内精品久久久久久久久久 | 国产精品成人aaaa在线 | a∨鲁丝一区鲁丝二区鲁丝三区 | 欧美性受xxxx白人性爽 | 久久久成 | 国产精品传媒在线 | 天天激情站 | 成人免费高清 | 波多野结衣成人在线 | 国产美女无遮挡免费视频 | 久久精品人妻一区二区三区 | 日本在线视频免费观看 | 日韩一区免费 | 中文在线日本 | 日日av| 美女免费看片 | 麻豆传媒在线看 | 日日夜夜国产精品 | 国产午夜精品福利 | 色图自拍 | 午夜影院免费看 | 国产在线色视频 | 久久亚洲无码视频 | 欧美黑人孕妇孕交 | 欧州一区二区三区 | 人体私拍套图hdxxxx | 多男调教一女折磨高潮高h 国内毛片毛片毛片毛片毛片 | 99自拍偷拍视频 | 亚洲精品wwww | 性大毛片视频 | 午夜精品久久久久久久久久久久 | 激情久久中文字幕 | 久久人人爽人人爽人人片av免费 | xxxxx黄色| 午夜精品久久久久久久四虎美女版 | 亚洲成人精品久久久 | 麻豆一区二区三区在线观看 | 借种(出轨高h) | 成年人视频免费看 | 中文字幕在线资源 | 亚洲在线视频免费观看 | 国产免费又爽又色又粗视频 | 影音先锋精品 | 一级不卡毛片 | 亚洲av无码专区在线 | 精品91久久久久久 | av色图片 | 国产一级片播放 | 不卡的中文字幕 | 蜜臀av中文字幕 | 97精品人妻一区二区三区蜜桃 | 久久精品香蕉视频 | 亚洲欧美综合视频 | 中文字幕国产日韩 | 国内特级毛片 | 春宵av| 九九热在线观看视频 | 色哟哟一区二区三区 | 蜜桃视频污在线观看 | 亚洲区自拍 | 在线观看黄色免费视频 | 岛国一区 | 欧洲精品免费一区二区三区 | 豆花av在线 | 69亚洲乱人伦| 久久狠狠爱 | 国产一区二区视频网站 | 欧美日本在线观看 | 国产伦精品一区二区三区 | 夜夜激情网 | 玖玖爱在线精品视频 | 欧美色哟哟 | 清纯唯美亚洲激情 | 国产嫩草av | 日本视频黄 | 国产精品日 | 国模一区二区三区 | 91黄色国产 | 九九九九九热 | 精品无码久久久久久国产 | 狠狠躁夜夜躁人人爽视频 | 欧美丰满少妇 | 亚洲国内在线 | 免费看黄在线 | 老司机午夜免费福利 | 亚洲av片不卡无码久久 |