现象:
网上在解释程序开发过程中常见的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模型不用变动,而且对数据库只有一次性查询
不知是能讲清楚,至此结束,谢谢!