一、通過select語句實現延遲載入
在Mybatis中,延遲載入可以使用select語句來實現。假設我們有兩個表,一個是用戶表,一個是訂單表,用戶表中保存了用戶的基本信息,訂單表中保存了用戶的訂單信息。這兩個表之間是一對多關係,即一個用戶可以擁有多個訂單。
在使用Mybatis查詢一條用戶記錄時,如果需要同時查詢該用戶的所有訂單信息,需要在Mapper文件中定義如下的select語句:
<select id="getUserWithOrders" resultMap="userMap"> select * from user where id = #{userId} select * from order where user_id = #{userId} </select>
這樣的查詢會產生一個問題:在查詢用戶信息時,同時也會查詢該用戶的所有訂單信息,如果該用戶擁有數千條訂單信息,那麼查詢的效率就會非常低。此時,可以通過使用Mybatis的延遲載入來解決這個問題。
二、Mybatis延遲載入是什麼
Mybatis中的延遲載入,指的是當我們查詢一條記錄時,並不會立即查詢該記錄的關聯記錄,而是當我們需要訪問該關聯記錄時,才會進行查詢。這種方式可以有效提高查詢效率。
三、Mybatis延遲載入的原理面試題
Mybatis的延遲載入原理是什麼?
在Mybatis中,延遲載入是通過動態代理實現的。當我們調用一個延遲載入的關聯對象時,Mybatis會首先判斷該對象是否為空,如果為空,則調用Mapper介面中的方法,查詢該關聯對象。在查詢完成後,將查詢結果封裝到代理對象中,並返回該代理對象。
四、Mybatis延遲載入默認
Mybatis的延遲載入默認是關閉的。如果需要啟用延遲載入,則需要在配置文件中開啟相應的延遲載入項。
五、Mybatis延遲載入的實現方式
Mybatis中的延遲載入,有兩種實現方式:
1. 延遲載入關聯對象
延遲載入關聯對象,指的是只有在需要訪問關聯對象時,才會進行查詢。這種方式可以避免一次性查詢大量數據,提高查詢效率。
2. 延遲載入屬性
延遲載入屬性,指的是只有在需要訪問屬性時,才會進行查詢。這種方式可以避免查詢出大量無用的數據,提高查詢效率。
六、Mybatis延遲載入的原理
Mybatis中的延遲載入,通過動態代理的方式實現。在查詢時,如果需要延遲載入某個關聯對象或屬性,Mybatis會將該對象或屬性封裝到一個代理對象中,並返回該代理對象。
當我們訪問代理對象時,Mybatis會先判斷代理對象中是否已經載入了該關聯對象或屬性,如果沒有載入,則調用Mapper介面中的方法,查詢該關聯對象或屬性。在查詢完成後,將查詢結果封裝到代理對象中,並返回該代理對象。下次訪問該關聯對象或屬性時,直接返回代理對象中的值,不再進行查詢。
七、Mybatis延遲載入怎麼配置
Mybatis中的延遲載入需要在配置文件中進行配置。可以通過在Mapper文件中使用select標籤,並指定fetchType屬性的方式,來開啟延遲載入。
例如,在查詢用戶信息時,我們可以通過以下方式開啟延遲載入:
<resultMap id="userMap" type="user"> <result property="id" column="id"/> <result property="name" column="name"/> <result property="orders" column="id" select="getOrdersByUserId" fetchType="lazy"/> </resultMap> <select id="getUserById" resultMap="userMap"> select * from user where id = #{id} </select> <select id="getOrdersByUserId" resultMap="orderMap"> select * from order where user_id = #{id} </select>
在上面的代碼中,我們使用了resultMap來定義查詢結果的映射關係。其中,fetchType屬性指定了關聯對象的延遲載入方式。lazy表示延遲載入,即只有在需要訪問該關聯對象時,才會進行查詢。
八、Mybatis延遲載入沒反應
如果在使用Mybatis的延遲載入時,發現沒有生效,可能是由於以下幾個原因:
1. 配置文件中未開啟延遲載入
在使用延遲載入時,需要在配置文件中開啟相應的延遲載入項。如果未開啟,延遲載入是不會生效的。
2. 關聯對象已經被載入
如果一個關聯對象已經被載入過了,則再次訪問該對象時,不會觸發延遲載入。在這種情況下,可以考慮使用二級緩存。
3. 關聯對象不存在
如果一個關聯對象不存在,則再次訪問該對象時,也不會觸發延遲載入。在這種情況下,需要檢查關聯對象的外鍵值是否正確。
九、Mybatis二級緩存
Mybatis中的二級緩存,是用來緩存Mapper文件中的查詢結果的。在需要查詢相同結果集時,如果已經存在於緩存中,就可以直接從緩存中獲取結果,而不需要再次進行查詢。這樣可以有效提高查詢效率。
在使用Mybatis的延遲載入時,可以使用二級緩存來避免多次查詢同一條記錄的關聯對象。當一個關聯對象已經被載入過了,可以將該對象緩存到二級緩存中。在下次訪問該關聯對象時,就可以直接從緩存中獲取,而不再進行查詢。
在Mybatis中,可以通過在配置文件中開啟二級緩存和指定緩存類型來開啟二級緩存。例如:
<settings> <setting name="cacheEnabled" value="true"/> </settings> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
在上面的代碼中,我們開啟了二級緩存,並指定了緩存類型為Ehcache。如果需要使用其他類型的緩存,可以在type屬性中指定相應的緩存類型。
十、Mybatis延遲載入附源碼
以下是使用Mybatis實現延遲載入的源碼:
public interface UserMapper { User getUserWithOrders(long userId); } // Mapper文件中的查詢語句 <select id="getUserWithOrders" resultMap="userMap"> select * from user where id = #{userId} select * from order where user_id = #{userId} </select> public class UserMapperImpl implements UserMapper { private final SqlSession sqlSession; private final OrderMapper orderMapper; public UserMapperImpl(SqlSession sqlSession, OrderMapper orderMapper) { this.sqlSession = sqlSession; this.orderMapper = orderMapper; } @Override public User getUserWithOrders(long userId) { User user = sqlSession.selectOne("getUserById", userId); user.setOrders(() -> orderMapper.getOrdersByUserId(userId)); return user; } } public interface OrderMapper { List<Order> getOrdersByUserId(long userId); } // Mapper文件中的查詢語句 <select id="getOrdersByUserId" resultMap="orderMap"> select * from order where user_id = #{userId} </select> public class OrderMapperImpl implements OrderMapper { private final SqlSession sqlSession; public OrderMapperImpl(SqlSession sqlSession) { this.sqlSession = sqlSession; } @Override public List<Order> getOrdersByUserId(long userId) { return sqlSession.selectList("getOrdersByUserId", userId); } } public class User { private long id; private String name; private List<Order> orders; // getters and setters } public class Order { private long id; private long userId; private String content; // getters and setters } public interface LazyLoader<V> { V load(); } public class LazyObject<T> implements Serializable { private static final long serialVersionUID = 1L; private final LazyLoader<T> loader; private T value; public LazyObject(LazyLoader<T> loader) { this.loader = loader; } public T getValue() { if (value == null) { value = loader.load(); } return value; } } public class LazyList<T> extends ArrayList<T> implements Serializable { private static final long serialVersionUID = 1L; private final LazyLoader<List<T>> loader; public LazyList(LazyLoader<List<T>> loader) { this.loader = loader; add(null); } @Override public T get(int index) { T value = super.get(index); if (value == null) { List<T> list = loader.load(); if (list != null && list.size() > index) { value = list.get(index); set(index, value); } } return value; } }
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/284509.html