一、一对多
1.首先创建数据库和表。两张表的id字段是自动递增的。
给category表录入两条数据,可自行添加记录。
INSERT INTO `category` VALUES (1, '我是分类1');
INSERT INTO `category` VALUES (2, '我是分类2');
INSERT INTO `product` VALUES (1, '我是分类1下的商品1', 999.20, 1);
INSERT INTO `product` VALUES (2, '我是分类1下的第二个商品', 666.30, 1);
INSERT INTO `product` VALUES (3, '我是分类2的第一个商品', 56.30, 2);
INSERT INTO `product` VALUES (4, '我是分类2下的第二个商品', 79.60, 2);
2.使用IDEA创建maven项目。下面一步步创建文件模拟一对多,
项目实现一对多、多以对、多对多最终结构图如下图:
添加依赖和jdk编译版本:
-
<dependencies>
-
<!--数据库连接驱动-->
-
<dependency>
-
<groupId>mysql
</groupId>
-
<artifactId>mysql-connector-java
</artifactId>
-
<version>5.1.46
</version>
-
</dependency>
-
<!--mybatis-->
-
<dependency>
-
<groupId>org.mybatis
</groupId>
-
<artifactId>mybatis
</artifactId>
-
<version>3.3.0
</version>
-
</dependency>
-
<dependency>
-
<groupId>junit
</groupId>
-
<artifactId>junit
</artifactId>
-
<version>4.12
</version>
-
</dependency>
-
</dependencies>
-
-
<!--配置编译源代码的jdk版本-->
-
<build>
-
<plugins>
-
<plugin>
-
<artifactId>maven-compiler-plugin
</artifactId>
-
<configuration>
-
<source>1.8
</source>
-
<target>1.8
</target>
-
</configuration>
-
</plugin>
-
</plugins>
-
</build>
3.创建和数据库表对应的pojo。
-
这个实体中新加了一个数据库没有的字段products,用于存放分类对应的商品集合。
-
-
public
class Category {
-
-
private
int id;
-
private String name;
-
private List<Product> products;
-
-
public List<Product> getProducts() {
-
return products;
-
}
-
public void setProducts(List<Product> products) {
-
this.products = 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;
-
}
-
-
@Override
-
public String toString() {
-
return
"Category{" +
-
"id=" + id +
-
", name='" + name +
'\'' +
-
'}';
-
}
-
}
这个实体目前还未加新的字段。
-
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 +
-
'}';
-
}
-
}
4.创建mybatis的配置文件。
-
<?xml version="1.0" encoding="UTF-8" ?>
-
<!DOCTYPE configuration
-
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
-
"http://mybatis.org/dtd/mybatis-3-config.dtd">
-
<configuration>
-
<typeAliases>
<!--设置别名-->
-
<package name="com.byh.pojo"/>
-
</typeAliases>
-
<!--连接数据库-->
-
<environments default="development">
-
<environment id="development">
-
<transactionManager type="JDBC"/>
-
<dataSource type="POOLED">
-
<property name="driver" value="com.mysql.jdbc.Driver"/>
-
<property name="url" value="jdbc:mysql://localhost:3306/dbmybatis?characterEncoding=UTF-8"/>
-
<property name="username" value="root"/>
-
<property name="password" value="admin"/>
-
</dataSource>
-
</environment>
-
</environments>
-
<!--扫描mapper文件-->
-
<mappers>
-
<mapper resource="mapper/CategoryMapper.xml"/>
-
</mappers>
-
-
</configuration>
5.创建CategoryMapper.xml。注意:namespace的值要是对应的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="com.byh.mapper.CategoryMapper">
-
-
<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>
-
<!-- 关联查询分类和商品表
-
通过left join关联查询,对Category和Product表进行关联查询。
-
这里不是用的resultType, 而是resultMap,通过resultMap把数据取出来放在对应的对象属性里,
-
通过指定列名映射实体具体的字段赋值。
-
Category的id 字段 和Product的id字段同名,Mybatis不知道谁是谁的,所以需要通过取别名cid,pid来区分。name字段同理。
-
-->
-
<select id="list" resultMap="categoryBean">
-
select c.id as 'cid', c.name as 'cname',p.id as 'pid', p.name as 'pname' ,p.price
-
from
-
category c left join product p
-
on
-
c.id = p.cid
-
</select>
-
-
</mapper>
6.创建CategoryMapper.java接口。
-
public
interface CategoryMapper {
-
-
List<Category>
list();
-
-
}
7.测试一对多关系。
-
import com.byh.mapper.CategoryMapper;
-
import com.byh.pojo.Category;
-
import com.byh.pojo.Product;
-
import org.apache.ibatis.io.Resources;
-
import org.apache.ibatis.session.SqlSession;
-
import org.apache.ibatis.session.SqlSessionFactory;
-
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
-
import org.junit.Before;
-
import org.junit.Test;
-
-
import java.io.IOException;
-
import java.io.InputStream;
-
import java.util.List;
-
-
public
class Demo2 {
-
-
private
SqlSession session;
-
private
CategoryMapper categoryMapper;
-
-
@
Before
-
public void bef()
throws
IOException {
-
//读取mybatis配置文件
-
InputStream inputStream =
Resources.getResourceAsStream(
"mybatis-config.xml");
-
//构建sqlSession的工厂
-
SqlSessionFactory sessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
-
//创建能执行映射文件中sql的sqlSession
-
session=sessionFactory.openSession();
-
//获得mapper
-
categoryMapper = session.getMapper(
CategoryMapper.
class);
-
}
-
-
@
Test
-
public void test(){
-
List<
Category> list = categoryMapper.list();
-
for(
Category
c : list){
-
System.out.
println(
c);
-
List<
Product> products =
c.getProducts();
-
for(
Product product : products){
-
System.out.
println(
"\t"+product);
-
}
-
System.out.
println(
"当前循环结束");
-
}
-
}
-
-
}
二、多以一
1.接着上面的项目写,在Product.java中添加分类字段:记得都要添加get、set方法。
2.创建ProductMapper.java接口。
-
package com.byh.mapper;
-
-
import com.byh.pojo.Product;
-
-
import java.util.List;
-
-
public
interface ProductMapper {
-
List<Product> productList();
-
}
3.创建对应的mapper.xml。ProductMapper.xml如下:
注意这里多对一中指定属性类型用的是javaType,跟一对多不一样。namespace中也要指定到对应的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="com.byh.mapper.ProductMapper">
-
-
<resultMap id="productBean" type="Product">
-
<id column="pid" property="id"/>
-
<result column="pname" property="name"/>
-
<!-- 多以一 -->
-
<!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
-
<association property="category" javaType="Category">
-
<id column="cid" property="id"/>
-
<result column="cname" property="name"/>
-
</association>
-
</resultMap>
-
-
<select id="productList" resultMap="productBean">
-
select c.id as 'cid', c.name as 'cname',p.id as 'pid', p.name as 'pname' ,p.price
-
from
-
category c left join product p
-
on
-
c.id = p.cid
-
</select>
-
-
</mapper>
4.测试:在之前的demo中添加ProductMapper。
添加测试方法:
-
@
Test
-
public
void
test02
(){
-
List<Product>
list = productMapper.productList();
-
for(Product p :
list){
-
-
System.out.println(p+
"对应的分类:"+p.getCategory());
-
}
-
}
结果:
三、多对多
1.数据库再新建两张表:
录入模拟多对多的数据:
INSERT INTO `order` VALUES (1, '编号A');
INSERT INTO `order` VALUES (2, '编号B');
INSERT INTO `order_item` VALUES (null, 1, 1, 52);
INSERT INTO `order_item` VALUES (null, 1, 2, 53);
INSERT INTO `order_item` VALUES (null, 1, 3, 54);
INSERT INTO `order_item` VALUES (null, 2, 2, 55);
INSERT INTO `order_item` VALUES (null, 2, 3, 56);
INSERT INTO `order_item` VALUES (null, 2, 4, 57);
2.创建两个实体:Order.java,其中添加了orderItemList字段,表示订单下的订单项。
-
public
class Order {
-
private
int id;
-
private String code;
-
//表明订单中有哪些订单项
-
private List<OrderItem> orderItemList;
-
-
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> getOrderItemList() {
-
return orderItemList;
-
}
-
public void setOrderItemList(List<OrderItem> orderItemList) {
-
this.orderItemList = orderItemList;
-
}
-
}
和OrderItem.java,注意这里跟数据库中有两个字段不一样,这里用的是对应的实体。product、order。
-
public
class OrderItem {
-
private
int id;
-
private
int number;
-
//这里添加了商品和订单,用于表明一个订单项属于中具体是哪个商品和在哪个订单中
-
private Product product;
-
private Order order;
-
-
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 Product getProduct() {
-
return product;
-
}
-
public void setProduct(Product product) {
-
this.product = product;
-
}
-
public Order getOrder() {
-
return order;
-
}
-
public void setOrder(Order order) {
-
this.order = order;
-
}
-
}
3.创建OrderMapper.xml,这里的resultMap我个人觉得绕了一点,但是理清思路也就感觉缺一不可。
-
<?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="com.byh.mapper.OrderMapper">
-
<!--这里比较绕
-
查询后id和code字段放在Order对象里,
-
然后通过一对多的<collection>标签把oiid和number放在OrderItem对象里,
-
最后把pid,pname,price放进Product对象里
-
-->
-
<resultMap id="orderBean" type="Order">
-
<id column="oid" property="id"/>
-
<result column="code" property="code"/>
-
<!--这里关联订单和所属的订单项的数据 一对多 -->
-
<collection property="orderItemList" 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="orderList" resultMap="orderBean">
-
select o.id 'oid',o.code, oi.id 'oiid',oi.number, p.name 'pname', p.id 'pid',p.price
-
from `order` o
-
left join order_item oi on o.id =oi.oid
-
left join product p on p.id = oi.pid
-
</select>
-
-
</mapper>
4.写对应的order的接口。这里只有一个list的接口。
-
public
interface OrderMapper {
-
-
List<Order> orderList();
-
-
}
5.一定要记得把xml文件添加到mybatis的映射文件中,不然会报错。
.
6.测试。在demo2.java中获得ordermapper。并调用orderList方法。
-
@
Test
-
public
void
test03(
){
-
List<Order> os = orderMapper.orderList();
//订单列表
-
for (Order o : os) {
-
System.
out.println(o.getCode());
//所有订单编号
-
List<OrderItem> ois= o.getOrderItemList();
//每个订单下的订单项
-
for (OrderItem oi : ois) {
//每个订单项下的商品信息
-
System.
out.println(
"商品:"+oi.getProduct().getName()+
" 价格:"+oi.getProduct().getPrice()+
" 数量:"+oi.getNumber());
-
}
-
}
-
}
输出结果:
接下来做添加订单项的准备工作:
1.创建OrderItemMapper.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="com.byh.mapper.OrderItemMapper">
-
-
<insert id="addOrderItem" parameterType="OrderItem">
-
insert into order_item values(null,#{order.id},#{product.id},#{number})
-
</insert>
-
<insert id="delOrderItem" parameterType="OrderItem">
-
delete from order_item where oid = #{order.id} and pid = #{product.id}
-
</insert>
-
-
</mapper>
2.创建OrderItemMapper接口。
-
public
interface OrderItemMapper {
-
void addOrderItem(OrderItem orderItem);
-
void delOrderItem(OrderItem orderItem);
-
}
3.mybatis加入配置文件。
4.OrderMapper.xml加入:
-
<
select id=
"getOrder" resultMap=
"orderBean">
-
select o.id
'oid',o.code, oi.id
'oiid',oi.number, p.name
'pname', p.id
'pid',p.price
-
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>
OrderMapper接口中添加方法:
ProductMapper.xml同理:
-
<
select id=
"getProduct" resultMap=
"productBean">
-
select c.id
as
'cid', c.name
as
'cname',p.id
as
'pid', p.name
as
'pname' ,p.price
-
from
-
category c left
join product p
-
on
-
c.id = p.cid
-
where p.id=
#{id}
-
</
select>
5.测试添加订单和删除订单:
引入新的mapper:
测试方法:
-
@Test
//添加订单项
-
public void test04(){
-
order();
//调用上面的查询所有订单的方法
-
System.out.println(
"-----------------------------添加新的订单项后----------------------------:");
-
Product p = productMapper.getProduct(
1);
-
Order o = orderMapper.getOrder(
2);
-
OrderItem orderItem =
new OrderItem();
-
orderItem.setOrder(o);
//设置订单项所属订单
-
orderItem.setProduct(p);
//订单项所属商品
-
orderItem.setNumber(
1001);
-
orderItemMapper.addOrderItem(orderItem);
-
order();
-
//不加这两句 添加的数据是不会应用到数据库的
-
session.commit();
-
session.close();
-
}
-
-
@Test
-
public void del(){
-
order();
//调用上面的查询所有订单的方法
-
System.out.println(
"-----------------------------删除订单项后----------------------------:");
-
Product p = productMapper.getProduct(
1);
-
Order o = orderMapper.getOrder(
2);
-
OrderItem orderItem =
new OrderItem();
-
orderItem.setOrder(o);
//设置订单项所属订单
-
orderItem.setProduct(p);
//订单项所属商品
-
orderItemMapper.delOrderItem(orderItem);
-
order();
-
session.commit();
-
session.close();
-
}
最后做一个删除订单就删除对应订单下的订单项的例子:
1.OrderMapper.xml中添加:
-
<delete id=
"delOrder" parameterType=
"int" >
-
delete
from order_item
where oid =
#{id};
-
delete
from `
order`
where id=
#{id};
-
</delete>
OrderMapper接口中添加:
2.测试方法:
-
@Test
-
public void delOrder(){
-
order();
//调用上面的查询所有订单的方法
-
orderMapper.delOrder(
2);
-
System.out.println(
"------------删除订单后:订单项也删除了---------------");
-
order();
//调用上面的查询所有订单的方法
-
session.commit();
-
session.close();
-
}
报错:org.apache.ibatis.exceptions.PersistenceException,也就是orderMapper.delOrder(2);这一句调用的时候报错,这是因为这句中我们有两个sql语句。
应该在mybatis的配置文件连接数据库的url属性中加入:&allowMultiQueries=true就可以执行多条sql语句。
再次测试:OK。