本例演示通过分类对产品的一对多,暂时无需Product.xml
资源下载
网盘地址
提取码:eapr
一对多查询
1.数据库设置:
CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8;
use mybatis;
CREATE TABLE student (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
card_id int(11) NOT NULL,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE card (
id int(11) NOT NULL AUTO_INCREMENT,
number int(11) NOT NULL,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO student VALUES (1,'student1',1);
INSERT INTO student VALUES (2,'student2',2);
INSERT INTO card VALUES (1,1111);
INSERT INTO card VALUES (2,2222);
- 注意: 这里并没有在数据库中设置外键,而是让 MyBatis 去处理多表之间的关系。事实上,外键只是用来保证数据一致性,在某些特殊的情况下(例如高并发秒杀系统中),会专门设置不适用外键,因为存在一定的性能损耗。
2.在java.pojo包下创建Categary.java,Product.java
package pojo;
import java.util.List;
public class Category {
private int id;
private String name;
List<Product> products;
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 List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
@Override
public String toString() {
return "Category [id=" + id + ", name=" + name + "]";
}
}
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 + "]";
}
}
3.配置mabatis-conf.xml与pom.xml
略,详见:(1)MyBatis入门
4.创建Category.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="Category" id="categoryBean">
<!-- id 标签表示对应的主键
column 对应查询结果的列值,起了别名所以与数据库的列名不一样
property 对应类中的属性名称
-->
<!--类Category的属性-->
<id column="cid" property="id" />
<result column="cname" property="name" />
<!-- 一对多的关系 -->
<!-- property: 指的是Category类集合属性的值, ofType:指的是集合中元素的类型,应该是类 -->
<collection property="products" ofType="Product">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
</collection>
</resultMap>
<!-- 关联查询分类和产品表 -->
<!--注: Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需d要通过取别名cid,pid来区分。name字段同理。-->
<select id="listCategory" 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>
5.创建测试类Test.java
public class Test
{
@org.junit.Test
public void test() throws IOException
{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
List<Category> cs = session.selectList("listCategory");
for (Category c : cs) {
System.out.println(c);
List<Product> ps = c.getProducts();
for (Product p : ps) {
System.out.println("\t"+p);
}
}
session.commit();
session.close();
}
}
6.运行
输出:
Category [id=1, name=category1]
Product [id=1, name=product a, price=88.88]
Product [id=2, name=product b, price=88.88]
Product [id=3, name=product c, price=88.88]
Category [id=2, name=category2]
Product [id=4, name=product x, price=88.88]
Product [id=5, name=product y, price=88.88]
Product [id=6, name=product z, price=88.88]
多对一查询
本知识点建立在一对多的基础上讲解多对一关系
1.修改Product.java
public class Product {
private int id;
private String name;
private float price;
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
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 + "]";
}
}
2.新建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">
<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>
3.在mybatis-config.xml中增加对于Product.xml的映射
<!-- 映射文件 -->
<mappers>
<mapper resource="pojo/Category.xml"/>
<mapper resource="pojo/Product.xml"/>
</mappers>
4.在测试类Test中添加第二个测试函数
@org.junit.Test
public void test2() throws IOException
{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
List<Product> ps = session.selectList("listProduct");
for (Product p : ps) {
System.out.println(p+" \t 对应的分类是 "+ p.getCategory());
}
session.commit();
session.close();
}
5.运行
Product [id=1, name=product a, price=88.88] 对应的分类是 Category [id=1, name=category1]
Product [id=2, name=product b, price=88.88] 对应的分类是 Category [id=1, name=category1]
Product [id=3, name=product c, price=88.88] 对应的分类是 Category [id=1, name=category1]
Product [id=4, name=product x, price=88.88] 对应的分类是 Category [id=2, name=category2]
Product [id=5, name=product y, price=88.88] 对应的分类是 Category [id=2, name=category2]
Product [id=6, name=product z, price=88.88] 对应的分类是 Category [id=2, name=category2]
多对多查询
本知识点是基于多对一的基础上进行。
在学习之前首先要理清楚多对多的关系,这里以订单Order和产品Product为例:
- 一张订单里 可以包含多种产品
- 一种产品 可以出现在多张订单里
这就是多对多关系
为了维系多对多关系,必须要一个中间表(数据库中的知识)。 在这里我们使用订单项(OrderItem)表来作为中间表。
1.在原先的数据库mybatis中新建表、导入数据
create table order_ (
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 order_ VALUES (1,'code000A');
INSERT INTO order_ 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);
表关系:
把order与product的多对多关系,转化成order与order_item的一对多关系,和order_item对product的多对一关系
2.创建实体类Order和OrderItem
package pojo;
import java.util.List;
public class Order {
private int id;
private String code;
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;
}
}
package pojo;
public class OrderItem {
private int id;
private int number;
private Order order;
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 getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
3.配置映射文件
Order.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="Order" id="orderBean">
<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="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
<select id="getOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ 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>
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">
<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>
<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>
<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>
</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>
4.修改mybatis-config.xml
在mappers中添加
<mapper resource="pojo/Order.xml"/>
<mapper resource="pojo/OrderItem.xml"/>
5.查询操作
原理:
通过Order.xml的listOrder对应的sql语句进行查询:
<select id="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
该sql语句将order_.id连接order_item_.oid,将order_item_.pid连接product_.id,最后结果是每个订单下的订单项,及订单项对应的产品信息。
Order.xml下的resultMap:
<resultMap type="Order" id="orderBean">
<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>
可以看出Order与OrderItem是一对多关系,OrderItem与Product是多对一关系。
查询结果 id和code字段放在Order对象里, 然后通过一对多的<collection>标签把oiid和number放在OrderItem对象里,最后把pid,pname,price放进Product对象里。
在测试类Test中添加第三个测试函数
/**
* 查询操作
* @throws IOException
*/
@org.junit.Test
public void test3() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
listOrder(session);
session.commit();
session.close();
}
private static void listOrder(SqlSession session) {
List<Order> os = session.selectList("listOrder");
for (Order o : os) {
System.out.println(o.getCode());
List<OrderItem> ois= o.getOrderItems();
for (OrderItem oi : ois) {
System.out.format("\t%s\t%f\t%d%n", oi.getProduct().getName(),oi.getProduct().getPrice(),oi.getNumber());
}
}
}
输出
code000A
product a 88.879997 100
product b 88.879997 100
product c 88.879997 100
code000B
product b 88.879997 100
product c 88.879997 100
product x 88.879997 100
6.建立关系
原理
让订单000A和产品z建立了关系:
要调用OrderItem.xml中的"addOrderItem":
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
</insert>
可以看到"addOrderItem"接收的参数是OrderItem
类。
所以我们要创建一个OrderItem
类,将Order与Product连接起来。
首先通过id分别获取Order对象和Product对象,然后创建一个新的OrderItem对象,接着设置Order,设置Product,设置数量(OrderItem的属性),最后调用"addOrderItem" 对应的sql语句插入数据。
java代码实现:
Order o1 = session.selectOne("getOrder", 1);
Product p6 = session.selectOne("getProduct", 6);
OrderItem oi = new OrderItem();
oi.setProduct(p6);
oi.setOrder(o1);
oi.setNumber(200);
session.insert("addOrderItem", oi);
在测试类Test中添加第四个测试函数
/**
* 建立关系
* @throws IOException
*/
@org.junit.Test
public void test4() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
addOrderItem(session);
listOrder(session);
session.commit();
session.close();
}
private static void addOrderItem(SqlSession session) {
//得到Order对象
Order o1 = session.selectOne("getOrder", 1);
//得到Product对象
Product p6 = session.selectOne("getProduct", 6);
//新建OrderItem对象
OrderItem oi = new OrderItem();
//设置OrderItem对象的三个属性,将Order与Product连接起来
oi.setProduct(p6);
oi.setOrder(o1);
oi.setNumber(200);
//调用OrderItem.xml中的addOrderItem
session.insert("addOrderItem", oi);
}
输出
code000A
product a 88.879997 100
product b 88.879997 100
product c 88.879997 100
product z 88.879997 200
code000B
product b 88.879997 100
product c 88.879997 100
product x 88.879997 100
7.删除关系
原理
所谓的删除关系,就是删除掉OrderItem记录。
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
</insert>
在测试类Test中添加第五个测试函数
@org.junit.Test
public void test5() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
deleteOrderItem(session);
listOrder(session);
session.commit();
session.close();
}
private static void deleteOrderItem(SqlSession session) {
Order o1 = session.selectOne("getOrder",1);
Product p6 = session.selectOne("getProduct",6);
OrderItem oi = new OrderItem();
oi.setProduct(p6);
oi.setOrder(o1);
session.delete("deleteOrderItem", oi);
}
输出
code000A
product a 88.879997 100
product b 88.879997 100
product c 88.879997 100
code000B
product b 88.879997 100
product c 88.879997 100
product x 88.879997 100
code000A
中没有product z
了。
8.修改关系
多对多不存在修改关系的做法,就是删除旧的,然后新增一条即达到修改的效果。