1. 程式人生 > >Mybatis的一對多、多對一、多對多例子

Mybatis的一對多、多對一、多對多例子

一、一對多

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屬性中加入:&amp;allowMultiQueries=true就可以執行多條sql語句。

再次測試:OK。