延遲加載和立即加載的概念
- 問題 :在一對(duì)多中逞盆,我們需要一個(gè)用戶檀蹋,他有100個(gè)賬戶
- 在查詢用戶的時(shí)候,要不要把關(guān)聯(lián)的賬戶查出來云芦?
在查詢用戶時(shí)俯逾,用戶下的賬戶信息應(yīng)該是,什么時(shí)候用舅逸,什么時(shí)候查詢的 - 在查詢賬戶的時(shí)候桌肴,要不要把關(guān)聯(lián)的用戶查出來?
在查詢賬戶時(shí)琉历,賬戶的所屬用戶信息應(yīng)該是隨著賬戶查詢時(shí)一起查詢出來
- 在查詢用戶的時(shí)候,要不要把關(guān)聯(lián)的賬戶查出來云芦?
- 什么是延遲加載
在真正使用數(shù)據(jù)時(shí)才發(fā)起查詢坠七,不用的時(shí)候不查詢,按需加載(懶加載) - 什么是立即加載
不管用不用旗笔,只要一調(diào)用方法彪置,馬上發(fā)起查詢 - 在對(duì)應(yīng)的四種表關(guān)系中:一對(duì)一,多對(duì)一蝇恶,一對(duì)多拳魁,多對(duì)多
一對(duì)多,多對(duì)多:通常情況下我們都是采用延遲加載
多對(duì)一撮弧,一對(duì)一:通常情況下我們都是采用立即加載
mybatis一對(duì)一實(shí)現(xiàn)延遲加載
<!--配置參數(shù)-->
<settings>
<!--開啟Mybatis支持延遲加載-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
settings
- IAccountDao.xml
<?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.IAccountDao"> <!-- 定義封裝account和user的resultMap --> <resultMap id="accountUserMap" type="account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- 一對(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"></association> </resultMap> <!-- 查詢所有 --> <select id="findAll" resultMap="accountUserMap"> select * from account </select> <!-- 根據(jù)用戶id查詢賬戶列表 --> <select id="findAccountByUid" resultType="account"> select * from account where uid = #{uid} </select> </mapper>
延遲加載.png
mybaits一對(duì)多實(shí)現(xiàn)延遲加載
- IUserDao.xml
<?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">
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user對(duì)象中accounts集合的映射 -->
<collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
<!-- 根據(jù)id查詢用戶 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{uid}
</select>
</mapper>
緩存的概念
- 什么是緩存
存在于內(nèi)存中的臨時(shí)數(shù)據(jù) - 為什么使用緩存
減少和數(shù)據(jù)庫的交互次數(shù),提高執(zhí)行效率 - 什么樣的數(shù)據(jù)能使用緩存贿衍,什么樣的數(shù)據(jù)不能使用
- 適用于緩存:
- 經(jīng)常查詢并且不經(jīng)常改變的
- 數(shù)據(jù)的正確與否對(duì)最終結(jié)果影響不大的
- 不適用于緩存:
- 經(jīng)常改變的數(shù)據(jù)
- 數(shù)據(jù)的正確與否對(duì)最終結(jié)果影響很大的
- 例如:商品的庫存授舟,銀行的匯率,股市的牌價(jià)
- 適用于緩存:
mybatis中的一級(jí)緩存
-
一級(jí)緩存:
它指的是Mybatis中SqlSession對(duì)象的緩存贸辈。 當(dāng)我們執(zhí)行查詢之后释树,查詢的結(jié)果會(huì)同時(shí)存入到SqlSession為我們提供一塊區(qū)域中。 該區(qū)域的結(jié)構(gòu)是一個(gè)Map裙椭。當(dāng)我們再次查詢同樣的數(shù)據(jù)躏哩,mybatis會(huì)先去sqlsession中查詢是否有,有的話直接拿出來用揉燃。 當(dāng)SqlSession對(duì)象消失時(shí),mybatis的一級(jí)緩存也就消失了筋栋。
-
測試一級(jí)緩存:
/** * 測試一級(jí)緩存 */ @Test public void testFirstLevelCache(){ User user1 = userDao.findById(41); System.out.println(user1); User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); //true }
-
關(guān)閉SqlSession:
/** * 測試一級(jí)緩存 */ @Test public void testFirstLevelCache(){ User user1 = userDao.findById(41); System.out.println(user1); // sqlSession.close(); //再次獲取SqlSession對(duì)象 // sqlSession = factory.openSession(); sqlSession.clearCache();//此方法也可以清空緩存 userDao = sqlSession.getMapper(IUserDao.class); User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); //false }
觸發(fā)清空一級(jí)緩存的情況
一級(jí)緩存是SqlSession范圍的緩存炊汤,當(dāng)調(diào)用SqlSession的修改,添加,刪除抢腐,commit(),close()等方法時(shí)姑曙,就會(huì)清空一級(jí)緩存。
-
測試
/** * 測試緩存的同步 */ @Test public void testClearlCache(){ //1.根據(jù)id查詢用戶 User user1 = userDao.findById(41); System.out.println(user1); /* //2.更新用戶信息 user1.setUsername("update user clear cache"); user1.setAddress("北京市海淀區(qū)"); userDao.updateUser(user1);*/ //3.再次查詢id為41的用戶 User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); //true }
/** * 測試緩存的同步 */ @Test public void testClearlCache(){ //1.根據(jù)id查詢用戶 User user1 = userDao.findById(41); System.out.println(user1); //2.更新用戶信息 user1.setUsername("update user clear cache"); user1.setAddress("北京市海淀區(qū)"); userDao.updateUser(user1); //3.再次查詢id為41的用戶 User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); //false }
mybatis的二級(jí)緩存
-
二級(jí)緩存:
它指的是Mybatis中SqlSessionFactory對(duì)象的緩存迈倍。由同一個(gè)SqlSessionFactory對(duì)象創(chuàng)建的SqlSession共享其緩存
二級(jí)緩存.png -
二級(jí)緩存的使用步驟:
- 第一步:讓Mybatis框架支持二級(jí)緩存(在SqlMapConfig.xml中配置)
- 第二步:讓當(dāng)前的映射文件支持二級(jí)緩存(在IuseDao.xml中配置)
- 第三步:讓當(dāng)前的操作支持二級(jí)緩存(在select標(biāo)簽中配置)
-
代碼
- SqlMapConfig.xml
<settings> <setting name="cacheEnabled" value="true"/> </settings>
- IuseDao.xml
<?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"> <!--開啟user支持二級(jí)緩存--> <cache/> <!-- 查詢所有 --> <select id="findAll" resultType="user"> select * from user </select> <!-- 根據(jù)id查詢用戶 --> <select id="findById" parameterType="INT" resultType="user" useCache="true"> select * from user where id = #{uid} </select> <!-- 更新用戶信息--> <update id="updateUser" parameterType="user"> update user set username=#{username},address=#{address} where id=#{id} </update> </mapper>
- SecondLevelCacheTest.java
package com.itheima.test; import com.itheima.dao.IUserDao; import com.itheima.domain.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.InputStream; /** * @author 黑馬程序員 * @Company http://www.ithiema.com */ public class SecondLevelCacheTest { private InputStream in; private SqlSessionFactory factory; @Before//用于在測試方法執(zhí)行之前執(zhí)行 public void init()throws Exception{ //1.讀取配置文件伤靠,生成字節(jié)輸入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.獲取SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); } @After//用于在測試方法執(zhí)行之后執(zhí)行 public void destroy()throws Exception{ in.close(); } /** * 測試一級(jí)緩存 */ @Test public void testFirstLevelCache(){ SqlSession sqlSession1 = factory.openSession(); IUserDao dao1 = sqlSession1.getMapper(IUserDao.class); User user1 = dao1.findById(41); System.out.println(user1); sqlSession1.close();//一級(jí)緩存消失 SqlSession sqlSession2 = factory.openSession(); IUserDao dao2 = sqlSession2.getMapper(IUserDao.class); User user2 = dao2.findById(41); System.out.println(user2); sqlSession2.close(); System.out.println(user1 == user2); } }
- SqlMapConfig.xml