1. 什么是延遲加載
舉個例子:如果查詢訂單并且關聯查詢用戶信息。如果先查詢訂單信息即可滿足要求,當我們需要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。 所以延遲加載即先從單表查詢、需要時再從關聯表去關聯查詢,大大提高數據庫性能,因為查詢單表要比關聯查詢多張表速度要快。
我們來對比一下:
關聯查詢:SELECT orders.*, user.username FROM orders, USER WHERE orders.user_id = user.id 延遲加載相當于: SELECT orders.*, (SELECT username FROM USER WHERE orders.user_id = user.id)username FROM orders
所以這就比較直觀了,也就是說,我把關聯查詢分兩次來做,而不是一次性查出所有的。第一步只查詢單表orders,必然會查出orders中的一個user_id字段,然后我再根據這個user_id查user表,也是單表查詢。下面來總結一下如何使用這個延遲加載
2. 使用association實現延遲加載
前面博文中總結了resultMap可以實現高級映射(使用association、collection實現一對一及一對多映射),其實association和collection還具備延遲加載的功能,這里我就拿association來說明,collection和association使用的方法都是一樣的。需求就是上面提到的,查詢訂單并且關聯查詢用戶,查詢用戶使用延遲加載。
由上面的分析可知,延遲加載要查詢兩次,第二次是按需查詢,之前一對一關聯查詢的時候只需要查一次,把訂單和用戶信息都查出來了,所以只要寫一個mapper即可,但是延遲加載查兩次,所以理所當然要有兩個mapper。
2.1 兩個mapper.xml
需要定義兩個mapper的方法對應的statement。先來分析一下思路:
- 只查詢訂單信息的statement,使用resultMap
- 通過查詢到的訂單信息中的user_id去查詢用戶信息的statement,得到用戶
- 定義的resultMap將兩者關聯起來,即用訂單信息user_id去查用戶
下面來實現這個思路:
1. 只查詢訂單信息的statement:
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap"> SELECT * FROM orders </select>
2. 只查詢用戶信息的statement:
<select id="findUserById" parameterType="int" resultType="user"> select * from user where id = #{id} </select>
3. 定義上面那個resultMap:
2.2 延遲加載的配置
mybatis默認沒有開啟延遲加載,需要在SqlMapConfig.xml中setting配置。前面一篇博文中提到SqlMapConfig.xml中的一些配置,有一個<settings>
,當時沒說,這里就派上用場了,可以通過這個標簽來配置一下延遲加載。
<settings> <!-- 打開延遲加載的開關 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 將積極加載改為消極加載,即延遲加載 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
2.3 mapper.java
別忘了寫mapper接口:
public interface UserMapperOrders { //省去不相關代碼 //查詢訂單,關聯用戶查詢,用戶查詢用的是延遲加載 public List<Orders> findOrdersUserLazyLoading() throws Exception; }
到此為止,延遲加載就做完了,下面來測試一下:
@Test public void testFindOrdersUserLazyLoading() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapperOrders userMapperOrders = sqlSession.getMapper(UserMapperOrders.class); //查詢訂單表(單表) List<Orders> list = userMapperOrders.findOrdersUserLazyLoading(); //遍歷上邊的訂單列表 for(Orders orders : list) { //執行getUser()去查詢用戶信息,這里實現按需加載 User user = orders.getUser(); System.out.println(user); } }
看一下執行結果:
執行結果很明顯,使用了延遲加載,將關聯查詢分成了兩次單表查詢,但是有個奇怪的地方,就是第二次查用戶的時候,并沒有發sql,而是直接就拿到了,其實這就是mybatis中的一級緩存,也是我下一篇博文要總結的東東。
文章列表