(3)MyBatis高级映射


本例演示通过分类对产品的一对多,暂时无需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为例:

  1. 一张订单里 可以包含多种产品
  2. 一种产品 可以出现在多张订单里

这就是多对多关系
为了维系多对多关系,必须要一个中间表(数据库中的知识)。 在这里我们使用订单项(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.修改关系

多对多不存在修改关系的做法,就是删除旧的,然后新增一条即达到修改的效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值