MyBatis的关系映射
1.一对多关系映射
本例建立在我的上一篇文章
MyBatis框架入门(一)的基础上,实现一个分类对应多个产品
新创建一个产品表
create table product(
id int NOT NULL AUTO_INCREMENT,
name varchar(30) DEFAULT NULL,
price float DEFAULT 0,
cid int ,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
清空category表和product表,插入新数据
delete from category;
INSERT INTO category VALUES (1,'category1');
INSERT INTO category VALUES (2,'category2');
delete from product;
INSERT INTO product VALUES (1,'product a', 88.88, 1);
INSERT INTO product VALUES (2,'product b', 88.88, 1);
INSERT INTO product VALUES (3,'product c', 88.88, 1);
INSERT INTO product VALUES (4,'product x', 88.88, 2);
INSERT INTO product VALUES (5,'product y', 88.88, 2);
INSERT INTO product VALUES (6,'product z', 88.88, 2);
创建Product实体类
package pojo;
public class Product {
private int id;
private String name;
private float price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
修改
Category实体类,提供products的集合
private List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
暂时
无需Product.xml
修改Category.xml
通过resultMap,进行字段和属性的对应
使用collection进行一对多关系关联,指定表字段名称与对象属性名称的一一对应关系
Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需要通过取别名cid,pid来区分。
name字段同理。
<?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="pojo">
<resultMap type="Category" id="categoryBean">
<id column="cid" property="id" />
<result column="cname" property="name" />
<!-- 一对多的关系 -->
<!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
<collection property="products" ofType="Product">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
</collection>
</resultMap>
<!-- 关联查询分类和产品表 -->
<select id="listCategories" resultMap="categoryBean">
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname' from category c left join product p on c.id = p.cid
</select>
</mapper>
在主类中测试one-to-many关系
// 一对多
List<Category> categories = session.selectList("listCategories");
for (Category category : categories) {
System.out.println(category);
List<Product> products = category.getProducts();
for (Product product : products) {
System.out.println("\t" + product);
}
}
2.多对一关系映射
本例实现多个Product对应一个Category关系映射
修改Product实体类,增加category属性
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
在同一个包中配置Product.xml
使用association 进行多对一关系关联,指定表字段名称与对象属性名称的一一对应关系
<?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="pojo">
<resultMap type="Product" id="productBean">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
<!-- 多对一的关系 -->
<!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
<association property="category" javaType="Category">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
<!-- 根据id查询Product, 关联将Orders查询出来 -->
<select id="listProduct" resultMap="productBean">
select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname' from category c left join product p on c.id = p.cid
</select>
</mapper>
在mybatis-config.xml中增加对于Product.xml的映射
<mapper resource="pojo/Product.xml"/>
在主类中测试many-to-one关系
// 多对一
List<Product> products = session.selectList("listProduct");
for (Product product : products) {
System.out.println(product + " 对应的分类是 \t " + product.getCategory());
}
3.多对多关系映射
本例实现多个Product对应多个Orders关系映射
要实现多对多关系映射,需要一张中间表,在本例中为
OrderItem
创建orders表和order_item表
create table orders (
id int(11) NOT NULL AUTO_INCREMENT,
code varchar(32) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
create table order_item(
id int(11) NOT NULL AUTO_INCREMENT,
oid int ,
pid int ,
number int ,
PRIMARY KEY(id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
插入数据
INSERT INTO orders VALUES (1,'code000A');
INSERT INTO orders VALUES (2,'code000B');
INSERT INTO order_item VALUES (null, 1, 1, 100);
INSERT INTO order_item VALUES (null, 1, 2, 100);
INSERT INTO order_item VALUES (null, 1, 3, 100);
INSERT INTO order_item VALUES (null, 2, 2, 100);
INSERT INTO order_item VALUES (null, 2, 3, 100);
INSERT INTO order_item VALUES (null, 2, 4, 100);
创建Orders实体类
package pojo;
import java.util.List;
public class Orders {
private int id;
private String code;
private List<OrderItem> orderItems;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
创建OrderItem实体类
package pojo;
public class OrderItem {
private int id;
private int number;
private Orders orders;
private Product product;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Order getOrders() {
return order;
}
public void setOrders(Order order) {
this.order = order;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
在同一包中配置Orders.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="pojo">
<resultMap type="Orders" id="ordersBean">
<id column="oid" property="id" />
<result column="code" property="code" />
<collection property="orderItems" ofType="OrderItem">
<id column="oiid" property="id" />
<result column="number" property="number" />
<association property="product" javaType="Product">
<id column="pid" property="id"/>
<result column="pname" property="name"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
<select id="listOrders" resultMap="ordersBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from orders o
left join order_item oi on o.id =oi.oid
left join product p on p.id = oi.pid
</select>
<select id="getOrders" resultMap="ordersBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from orders o
left join order_item oi on o.id =oi.oid
left join product p on p.id = oi.pid
where o.id = #{id}
</select>
</mapper>
在同一包中配置OrderItem.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="pojo">
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item
values(null,#{order.id},#{product.id},#{number})
</insert>
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item
where oid = #{order.id} and pid = #{product.id}
</insert>
</mapper>
修改Product.xml,添加getProduct.xml字段
<select id="getProduct" resultMap="productBean">
select c.*, p.*, c.id 'cid',
p.id 'pid', c.name 'cname', p.name 'pname'
from category c
left join
product p on c.id = p.cid
where p.id = #{id}
</select>
在mybatis-config.xml中添加对于Orders.xml和OrderItem的映射
<mapper resource="pojo/Orders.xml"/>
<mapper resource="pojo/OrderItem.xml"/>
在主类中测试many-to-many关系
public class App {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
// 多对多
listOrders(session);
addOrderItem(session);
deleteOrderItem(session);
session.commit();
session.close();
inputStream.close();
}
// 查询订单列表
private static void listOrder(SqlSession session) {
List<Orders> orders = session.selectList("listOrders");
for (Orders order : orders) {
System.out.println(order.getCode());
List<OrderItem> orderItems = order.getOrderItems();
for (OrderItem orderItem : orderItems) {
System.out.format("\t%s\t%f\t%d%n", orderItem.getProduct().getName(), orderItem.getProduct().getPrice(),
orderItem.getNumber());
}
}
}
// 建立关系
private static void addOrderItem(SqlSession session) {
Orders orders = session.selectOne("getOrders", 1);
Product product = session.selectOne("getProduct", 6);
OrderItem orderItem = new OrderItem();
orderItem.setProduct(product);
orderItem.setOrders(orders);
orderItem.setNumber(200);
session.insert("addOrderItem", orderItem);
}
// 删除关系
private static void deleteOrderItem(SqlSession session) {
Orders orders = session.selectOne("getOrders", 1);
Product product = session.selectOne("getProduct", 6);
OrderItem orderItem = new OrderItem();
orderItem.setProduct(product);
orderItem.setOrders(orders);
session.delete("deleteOrderItem", orderItem);
}
MyBatis的动态SQL
修改Product.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="pojo">
<!-- 如果没有传参数name,那么就查询所有,如果有name参数,那么就进行模糊查询。 -->
<select id="ifListProduct" resultType="Product">
select * from product
<if test="name != null">
where name like concat('%', #{name}, '%')
</if>
</select>
<!-- <where>标签会进行自动判断。如果任何条件都不成立,那么就在sql语句里就不会出现where关键字。如果有任何条件成立,会自动去掉多出来的
and 或者 or。 -->
<select id="whereListProduct" resultType="Product">
select * from product
<where>
<if test="name != null">
and name like concat('%", #{name}", '%')
</if>
<if test="price != null and price != 0">
and price > #{price}
</if>
</where>
</select>
<!-- 与where标签类似的,在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签 -->
<update id="setUpdateProduct" parameterType="Product">
update product
<set>
<if test="name != null">name = #{name},</if>
<if test="price != null">price = #{price}</if>
</set>
where id = #{id}
</update>
<!-- trim标签trim 用来定制想要的功能,将上面两个标签替换成trim -->
<select id="trimlistProduct" resultType="Product">
select * from product
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="trimprice!=null and price!=0">
and price > #{price}
</if>
</trim>
</select>
<update id="updateProduct" parameterType="Product">
update product
<trim prefix="SET" suffixOverrides=",">
<if test="name != null">name=#{name},</if>
<if test="price != null">price=#{price}</if>
</trim>
where id=#{id}
</update>
<!-- Mybatis里面没有else标签,但是可以使用when otherwise标签来达到这样的效果。 -->
<select id="chooseListProduct" resultType="Product">
SELECT * FROM product
<where>
<choose>
<when test="name != null">
and name like concat('%',#{name},'%')
</when>
<when test="price !=null and price != 0">
and price > #{price}
</when>
<otherwise>
and id >1
</otherwise>
</choose>
</where>
</select>
<!-- foreach标签通常用于in 这样的语法里,如例,如图查询出id等于1,3,5的数据出来。 -->
<select id="foreachListProduct" resultType="Product">
select * from product
where id in
<foreach item="item" index="index" collection="list" open="("
separator="," close=")">
#{item}
</foreach>
</select>
<!-- bind标签就像是再做一次字符串拼接,方便后续使用。如本例,在模糊查询的基础上,把模糊查询改为bind标签。 -->
<select id="bindListProductByName" resultType="Product">
<bind name="likename" value="'%' + name + '%'" />
select * from product where name like #{likename}
</select>
</mapper>
在主类中测试动态SQL功能
public class App {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
// if标签
System.out.println("查询所有的");
List<Product> products = session.selectList("ifListProduct");
for (Product product : products) {
System.out.println(product);
}
System.out.println("模糊查询");
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "a");
List<Product> products2 = session.selectList("ifListProduct", map);
for (Product product : products2) {
System.out.println(product);
}
// where标签
System.out.println("多条件查询");
Map<String, Object> map = new HashMap<String, Object>();
map.put("price", "10");
List<Product> products = session.selectList("whereListProduct", map);
for (Product product : products) {
System.out.println(product);
}
// set标签
Product product = new Product();
product.setId(6);
product.setName("product zz");
product.setPrice(99.99f);
session.update("setUpdateProduct", product);
whereListProduct(session);
// when otherwise标签
Map<String, Object> map = new HashMap<String, Object>();
map.put("price", 88.88);
List<Product> products = session.selectList("chooseListProduct", map);
for (Product product : products) {
System.out.println(product);
}
// foreach标签
List<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(3);
integers.add(5);
List<Product> products = session.selectList("foreachListProduct", integers);
for (Product product : products) {
System.out.println(product);
}
// bind标签 Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "product");
List<Product> products = session.selectList("bindListProductByName", map);
for (Product product : products) {
System.out.println(product);
}
session.commit();
session.close();
inputStream.close();
}
// 多条件查询
private static void whereListProduct(SqlSession session) {
Map<String, Object> map = new HashMap<String, Object>();
List<Product> products = session.selectList("whereListProduct", map);
for (Product product : products) {
System.out.println(product);
}
}
}