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)!这部分有些细节,多练练就搞清楚了!