MyBatis举例说明数据库查询1+n或者n+1问题

版权声明:转载请注明来源! https://blog.csdn.net/lstcui/article/details/83088713

现象:

网上在解释程序开发过程中常见的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模型不用变动,而且对数据库只有一次性查询

不知是能讲清楚,至此结束,谢谢!

猜你喜欢

转载自blog.csdn.net/lstcui/article/details/83088713