一、通過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-hk/n/284509.html
微信掃一掃
支付寶掃一掃