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