MyBatis延遲加載策略深入探究
有兩種寫法來表示查詢信息,分別是鏈表查詢和分步查詢的方法。那麼既然我麼能用一個SQL語句能夠執行完,那為什麼還要分開來寫呢?
原因很簡單:可以發現如果我們把他們連在一起那麼他們就是一個多表查詢語句,如果不放在一起執行,那那就是單獨一個表的查詢語句。但是這需要我們設置mybatis的延遲加載(懶加載)
分步查詢的優點
**可以實現延遲加載,**但是必須在核心配置文件中設置全局配置信息
lazyLoadingEnabled:延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載
aggressiveLazyLoding:當開啟時,任何方式的調用都會加載該對象的所有屬性。否則,該屬性會按需加載 ,此時就可以實現按需加載,需要獲取的數據是什麼,就隻會執行相應的sql.此時會通過association和collection中的fetchType屬性設置當前的分步查詢是否使用懶加載
fetchType=“lazy(延遲加載) | eager(立即加載)”
在主配置文件當中設置延遲加載
延遲加載:在SqlMapConfig.xml中配置延遲加載文件
<settings> <setting name="logImpl" value="STDOUT_LOGGING" /> <!-- 打印日志到控制臺上 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <!-- false才會按需加載,不開啟調用所有的對象 --> </settings>
在studentDao.xml當中設置分步查詢
測試結果
此時開啟瞭懶加載,實現瞭分佈查詢
如何使用
public class UserDO { private Integer userId; private String username; private String password; private String nickname; private List<PermitDO> permitDOList; public UserDO() {} }
<resultMap id="BaseMap" type="org.apache.ibatis.study.entity.UserDO"> <id column="user_id" jdbcType="INTEGER" property="userId" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="password" jdbcType="VARCHAR" property="password" /> <result column="nickname" jdbcType="VARCHAR" property="nickname"/> <collection property="permitDOList" column="user_id" select="getPermitsByUserId" fetchType="lazy"> </collection> </resultMap> <resultMap id="PermitBaseMap" type="org.apache.ibatis.study.entity.PermitDO"> <id column="id" jdbcType="INTEGER" property="id"/> <result column="code" jdbcType="VARCHAR" property="code"/> <result column="name" jdbcType="VARCHAR" property="name"/> <result column="type" jdbcType="TINYINT" property="type"/> <result column="pid" jdbcType="INTEGER" property="pid"/> </resultMap> <select id="getByUserId2" resultMap="BaseMap"> select * from user where user_id = #{userId} </select> <select id="getPermitsByUserId" resultMap="PermitBaseMap"> select p.* from user_permit up inner join permit p on up.permit_id = p.id where up.user_id = #{userId} </select>
通過fetchType=lazy指定子查詢getPermitsByUserId使用懶加載,這樣的話就不用管全局配置lazyLoadingEnabled是true還是false瞭。當然這裡可以直接用多表關聯查詢不使用子查詢,使用方法在這篇文章
測試代碼
public class Test { public static void main(String[] args) throws IOException { try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) { // 構建session工廠 DefaultSqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); UserDO userDO = userMapper.getByUserId2(1); System.out.println(userDO); } } }
結果如下,打瞭斷點可以看到原userDO對象已被代理並且permitDOList是null需要調用get方法才會去查詢拿到值,咳咳這邊之前直接運行顯示是已經把permitDOList查詢出來瞭,想瞭半天啥原因後來才發現println會調用userDO對象的toString方法,而toString方法也會走代理方法直接去調用子查詢的
延遲加載的好處
延遲加載主要能解決mybatis的N+1問題,什麼是N+1問題其實叫1+N更為合理,以上面的業務例子來說就是假設一次查詢出來10000個用戶,那麼還需要針對這10000個用戶使用子查詢getPermitsByUserId獲取每個用戶的權限列表,需要10000次查詢,總共10001次,真實情況下你可能並不需要每個子查詢的結果,這樣就浪費數據庫連接資源瞭。如果使用延遲加載的話就相當於不用進行這10000次查詢,因為它是等到你真正使用的時候才會調用子查詢獲取結果。
到此這篇關於MyBatis延遲加載策略深入探究的文章就介紹到這瞭,更多相關MyBatis延遲加載內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 一文瞭解mybatis的延遲加載
- Mybatis結果集映射與生命周期詳細介紹
- Mybatis中resultMap的Colum和property屬性詳解
- Mybatis一對多查詢列表屬性處理示例詳解
- 解讀Mapper與Mapper.xml文件之間匹配的問題