MyBatis舉例說明資料庫查詢1+n或者n+1問題
現象:
網上在解釋程式開發過程中常見的1+n或者n+1問題時,有的解釋不太詳細,初學者可能不太好理解;
現以Mybatis為例,解釋下該問題,如下:
1、場景:查詢出客戶基礎資訊及其訂單資訊
1.1 BOM模型設計:
Customer.java
public class Customer { private String customerId; private String cutomerName; private List<Order> orders; public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getCutomerName() { return cutomerName; } public void setCutomerName(String cutomerName) { this.cutomerName = cutomerName; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } }
Order.java
public class Order { private String orderId; private String customerId; private int num; private double total; public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public double getTotal() { return total; } public void setTotal(double total) { this.total = total; } }
1.2 Mybatis mapper.xml配置檔案:
-- 查詢客戶資訊 <resultMap type="Customers" id="customersResultMap" > <id column="customerId"/> <result property="customerName" column="customerName" javaType="string"/> <collection property="orders" ofType="Order" select="getCustOrders" column="{customerId=customerId}" /> </resultMap> <select id="loadCustomers" statementType="PREPARED" parameterType="java.util.HashMap" resultMap="customersResultMap"> select customerId, customerName from tb_customers </select> -- 查詢訂單資訊 <resultMap type="Order" id="customersResultMap" > <id column="customerId"/> <result property="orderId" column="orderId" javaType="string"/> <result property="num" column="num" javaType="string"/> <result property="total" column="total" javaType="string"/> </resultMap> <select id="getCustOrders" statementType="PREPARED" parameterType="java.util.HashMap" resultMap="customersResultMap"> select customerId, orderId, num, total from tb_order where customerId = #{customerId} </select>
2、結果說明
系統會先執行 loadCustomers 查詢語句,根據該查詢的結果遍歷執行 getCustOrders 查詢
即會造成如下執行過程
select customerId, customerName from tb_customers 1 次
select customerId, orderId, num, total from tb_order where customerId = 1
select customerId, orderId, num, total from tb_order where customerId = 2
select customerId, orderId, num, total from tb_order where customerId = 3
... ... ... ...
select customerId, orderId, num, total from tb_order where customerId = n
即造成最終執行結果為1+n次 也就是網上所說的1+n問題或者n+1問題 其實說1+n更確切些
造成的結果也就是給資料庫伺服器帶來不必要的壓力,可以想象我如果從tb_customers查詢出來的數量為1000, 每個人名下有20個訂單明細,資料庫的查詢量可想而知,那如果數量更大呢?
但如何才能避免類似的問題呢,其實很簡單,原理就是轉換下查詢思路,把想要的資料通過SQL語句一次性查詢出來,剩下的交由記憶體中處理,對此框架都是支援的,
即修改後如下:
-- 查詢客戶+訂單資訊
<resultMap type="Customers" id="customersResultMap" >
<id column="customerId"/>
<result property="customerName" column="customerName" javaType="string"/>
<collection property="orders" ofType="Order">
<id column="customerId"/>
<result property="orderId" column="orderId" javaType="string"/>
<result property="num" column="num" javaType="string"/>
<result property="total" column="total" javaType="string"/>
</collection>
</resultMap>
<select id="loadCustomers" statementType="PREPARED" parameterType="java.util.HashMap" resultMap="customersResultMap">
select customerId, customerName
from tb_customers cm
left join tb_order od
on cm.customerId = od.customerId
</select>
如上,BOM模型不用變動,而且對資料庫只有一次性查詢
不知是能講清楚,至此結束,謝謝!