MyBatis的关联映射

MyBatis的关联映射有三种:一对一,一对多,多对多。这里,我们对每一种映射关系都认真分析一下:

一对一:

实例:一个人对应一张身份证,一个身份证对应一个人。

创建两张表,person和card.。其中person表的字段有:id   name  age  sex   card_id。card表的字段有id   code

我们将card的id与person的card_id相对应,查询person时候,也关联查询对应的card。

创建过程以及Person和Card在此略过。

创建两个Mapper.xml,分别命名为CardMapper.xml和PersonMapper.xml,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily.mapper.CardMapper">
<select id="findCodeById" parameterType="Integer" resultType="Card">
SELECT * from tb_card where id=#{id}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily.mapper.PersonMapper">
<select id="findPersonById" parameterType="Integer" resultMap="getCodeByResultMap">
SELECT * from tb_person where id=#{id}
</select>
<resultMap type="Person" id="getCodeByResultMap">
	<id property="id" column="id"/>
	<result property="name" column="name"/>
	<result property="age" column="age"/>
	<result property="sex" column="sex"/>
	<association property="card" column="card_id" javaType="Card" select="ltd.ourfamily.mapper.CardMapper.findCodeById"/>
</resultMap>
</mapper>

可以看出,这里采用的时嵌套查询的方式来关联CardMapper,其中association标签的column将值传递给CardMapper.findCodeById,然后获取结果,转化为Card对象类型,最后显示出来。

但是嵌套查询意味着会重复执行,这样在高频率数据交互式显然效率太低,所以以上的Person可以换一种写法:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily.mapper.PersonMapper">
<select id="findPersonById" parameterType="Integer" resultMap="getCodeByResultMap">
SELECT p.*,c.code
from tb_person p,tb_card c
where p.card_id=c.id
and p.id=#{id}
</select>
<resultMap type="Person" id="getCodeByResultMap">
	<id property="id" column="id"/>
	<result property="name" column="name"/>
	<result property="age" column="age"/>
	<result property="sex" column="sex"/>
	<association property="card" javaType="Card">
		<id property="id" column="card_id"/>
		<result property="code" column="code"/>
	</association>
</resultMap>
</mapper>

很明显,这种利用编写比较复杂的sql多表联合查询语句比之前写两个Mapper.xml的方式更加简便和高效!

一对多:

一对多是我们日常生活中最为常见的,最典型的例子就是用户和订单,一个用户对应多个订单。

创建两张表,tb_user和tb_orders,其中tb_user的字段有:id   username  address   tb_orders字段有:id    number   user_id

tb_user的Bean如下:

package ltd.ourfamily2.po;

import java.util.List;

public class User {
	private Integer id;
	private String username;
	private String address;
	private List<Orders> orders;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public List<Orders> getOrders() {
		return orders;
	}
	public void setOrders(List<Orders> orders) {
		this.orders = orders;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", address=" + address + ", orders=" + orders + "]";
	}
	
}

然后我们这里只看看它的Mapper如何写:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily2.mapper.UserMapper">
<select id="findUserByIdWithOrders" parameterType="Integer" resultMap="UserWithOrders">
SELECT u.*,o.id as orders_id,o.number
from tb_user u,tb_orders o
where u.id=o.user_id
and u.id=#{id}
</select>
<resultMap type="User" id="UserWithOrders">
	<id property="id" column="id"/>
	<result property="username" column="username"/>
	<result property="address" column="address"/>
	<!-- 一对多关系使用collection,这里的ofType类似于JavaType -->
	<collection property="orders" ofType="Orders">
		<id property="id" column="orders_id"/>
		<result property="number" column="number"/>
	</collection>
</resultMap>
</mapper>

这里采用是嵌套结果的方式查询,就是编写多表查询的sql语句来查询。感觉大部分于一对一查询差不了多少,只是一对一采用的是association标签,采用JavaType来接受返回类型,而一对多采用的是collection标签,采用ofType来接受返回类型,其实javaType和ofType感觉差不多,只是运用的场景不同罢了!

多对多:

除了一对多,多对多在我们实际生活中也很常见。处理多对多,通常,我们是设置一个中间表,将两张表的主键设置为中间表的字段,每次查询时,先找到查询表的主键,根据主键找到中间表的所有字段,然后找到被查询表的主键列表,进而找到所有的关联表。这就是我们处理多对多的思路!

首先,创建三张表tb_orders和tb_product,以及关联表tb_orderitem。其中tb_orders的字段如上所示,tb_product的字段有id  name   price。  tb_ordersitem的字段有: id    orders_id     product_id

tb_orders的Bean如下:

package ltd.ourfamily3.po;

import java.util.List;

public class Orders {
	private Integer id;
	private String number;
	private List<Product> products;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public List<Product> getProducts() {
		return products;
	}
	public void setProducts(List<Product> products) {
		this.products = products;
	}
	@Override
	public String toString() {
		return "Orders [id=" + id + ", number=" + number + ", products=" + products + "]";
	}
}

tb_product的Bean如下:

package ltd.ourfamily3.po;

import java.util.List;

public class Product {
	private Integer id;
	private String name;
	private Double price;
	private List<Orders> orders;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	public List<Orders> getOrders() {
		return orders;
	}
	public void setOrders(List<Orders> orders) {
		this.orders = orders;
	}
	@Override
	public String toString() {
		return "Product [id=" + id + ", name=" + name + ", price=" + price + ", orders=" + orders + "]";
	}
	
}

创建两个Mapper.xml,分别命名为ProductMapper.xml和OrdersMapper.xml,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily3.mapper.OrdersMapper">
<select id="findOrdersWithProductById" parameterType="Integer" resultMap="ProductWithOrders">
	select * from tb_orders where id=#{id}
</select>
<resultMap type="Orders" id="ProductWithOrders">
	<id property="id" column="id"/>
	<result property="number" column="number"/>
	<!-- 一对多关系使用collection,这里的ofType类似于JavaType -->
	<collection property="products" ofType="Product" column="id" select="ltd.ourfamily3.mapper.ProductMapper.findProductsById"/>
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily3.mapper.ProductMapper">
<select id="findProductsById" parameterType="Integer" resultType="Product">
SELECT * from tb_product where id in(
	SELECT product_id from tb_ordersitem where orders_id=#{id}
)
</select>
</mapper>

首先,根据id获取到tb_orders的内容,然后根据id获取到tb_ordersitem中orders_id=id的数据,在根据获取到的product_id查询product中对应的数据,这样就实现了多对多的查询!同样的道理,我们也可以将这中嵌套查询改为嵌套结果,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="ltd.ourfamily3.mapper.OrdersMapper">
<select id="findOrdersWithProductById" parameterType="Integer" resultMap="ProductWithOrders">
	select o.*,p.id as pid,p.name,p.price
	from tb_orders o,tb_product p,tb_ordersitem s
	where s.orders_id=o.id and s.product_id=p.id and o.id=#{id}
</select>
<resultMap type="Orders" id="ProductWithOrders">
	<id property="id" column="id"/>
	<result property="number" column="number"/>
	<!-- 一对多关系使用collection,这里的ofType类似于JavaType -->
	<collection property="products" ofType="Product">
		<id property="id" column="pid"/>
		<result property="name" column="name"/>
		<result property="price" column="price"/>
	</collection>
</resultMap>
</mapper>

需要注意的是:查询另一张表(本例中的Product),有些参数需要重命名(如本例中的pid)!这部分有些细节,多练练就搞清楚了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值