延遲加載和立即加載的概念
- 問題 :在一對多中,我們需要一個用戶,他有100個賬戶
- 在查詢用戶的時候,要不要把關聯(lián)的賬戶查出來?
在查詢用戶時,用戶下的賬戶信息應該是,什么時候用,什么時候查詢的 - 在查詢賬戶的時候,要不要把關聯(lián)的用戶查出來?
在查詢賬戶時,賬戶的所屬用戶信息應該是隨著賬戶查詢時一起查詢出來
- 在查詢用戶的時候,要不要把關聯(lián)的賬戶查出來?
- 什么是延遲加載
在真正使用數(shù)據(jù)時才發(fā)起查詢,不用的時候不查詢,按需加載(懶加載) - 什么是立即加載
不管用不用,只要一調用方法,馬上發(fā)起查詢 - 在對應的四種表關系中:一對一,多對一,一對多,多對多
一對多,多對多:通常情況下我們都是采用延遲加載
多對一,一對一:通常情況下我們都是采用立即加載
mybatis一對一實現(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> <!-- 一對一的關系映射:配置封裝user的內(nèi)容 select屬性指定的內(nèi)容:查詢用戶的唯一標識: column屬性指定的內(nèi)容:用戶根據(jù)id查詢時,所需要的參數(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一對多實現(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對象中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ù)據(jù) - 為什么使用緩存
減少和數(shù)據(jù)庫的交互次數(shù),提高執(zhí)行效率 - 什么樣的數(shù)據(jù)能使用緩存,什么樣的數(shù)據(jù)不能使用
- 適用于緩存:
- 經(jīng)常查詢并且不經(jīng)常改變的
- 數(shù)據(jù)的正確與否對最終結果影響不大的
- 不適用于緩存:
- 經(jīng)常改變的數(shù)據(jù)
- 數(shù)據(jù)的正確與否對最終結果影響很大的
- 例如:商品的庫存,銀行的匯率,股市的牌價
- 適用于緩存:
mybatis中的一級緩存
-
一級緩存:
它指的是Mybatis中SqlSession對象的緩存。 當我們執(zhí)行查詢之后,查詢的結果會同時存入到SqlSession為我們提供一塊區(qū)域中。 該區(qū)域的結構是一個Map。當我們再次查詢同樣的數(shù)據(jù),mybatis會先去sqlsession中查詢是否有,有的話直接拿出來用。 當SqlSession對象消失時,mybatis的一級緩存也就消失了。 -
測試一級緩存:
/** * 測試一級緩存 */ @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 } -
關閉SqlSession:
/** * 測試一級緩存 */ @Test public void testFirstLevelCache(){ User user1 = userDao.findById(41); System.out.println(user1); // sqlSession.close(); //再次獲取SqlSession對象 // 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ā)清空一級緩存的情況
一級緩存是SqlSession范圍的緩存,當調用SqlSession的修改,添加,刪除,commit(),close()等方法時,就會清空一級緩存。
-
測試
/** * 測試緩存的同步 */ @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的二級緩存
-
二級緩存:
它指的是Mybatis中SqlSessionFactory對象的緩存。由同一個SqlSessionFactory對象創(chuàng)建的SqlSession共享其緩存
二級緩存.png -
二級緩存的使用步驟:
- 第一步:讓Mybatis框架支持二級緩存(在SqlMapConfig.xml中配置)
- 第二步:讓當前的映射文件支持二級緩存(在IuseDao.xml中配置)
- 第三步:讓當前的操作支持二級緩存(在select標簽中配置)
-
代碼
- 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支持二級緩存--> <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(); } /** * 測試一級緩存 */ @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();//一級緩存消失 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
