今天,我们将使用XML和注释配置来研究Hibernate多对多映射 。前面我们研究了如何在Hibernate中实现一到One和[一对多mapping](/community/tutorials/hibernate-one-to-many-mapping-annotationHibernate一到多映射
]。
多对多休眠
多对多 映射通常使用** JOIN表** 在数据库中实现。例如,我们可以有Cart
和Item
表,以及用于多对多映射的Cart_Items
表。每个购物车可以有多个项目,每个项目可以是多个购物车的一部分,所以我们在这里有一个多对多的映射。
Hibernate多对多映射数据库设置
下面的脚本可以用来创建我们的多对多示例数据库表,这些脚本用于MySQL数据库。如果您使用的是任何其他数据库,则可能需要进行一些小的更改才能使其正常工作。
1DROP TABLE IF EXISTS `Cart_Items`;
2DROP TABLE IF EXISTS `Cart`;
3DROP TABLE IF EXISTS `Item`;
4
5CREATE TABLE `Cart` (
6 `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
7 `cart_total` decimal(10,0) NOT NULL,
8 PRIMARY KEY (`cart_id`)
9) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
10
11CREATE TABLE `Item` (
12 `item_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
13 `item_desc` varchar(20) NOT NULL,
14 `item_price` decimal(10,0) NOT NULL,
15 PRIMARY KEY (`item_id`)
16) ENGINE=InnoDB DEFAULT CHARSET=utf8;
17
18CREATE TABLE `Cart_Items` (
19 `cart_id` int(11) unsigned NOT NULL,
20 `item_id` int(11) unsigned NOT NULL,
21 PRIMARY KEY (`cart_id`,`item_id`),
22 CONSTRAINT `fk_cart` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`),
23 CONSTRAINT `fk_item` FOREIGN KEY (`item_id`) REFERENCES `Item` (`item_id`)
24) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注意,Cart_Items表没有任何额外的列,实际上在多对多映射表中有额外的列没有多大意义。但如果你有额外的专栏,实现会有一些变化,我们将在另一篇文章中研究这一点。下图显示了这些表之间的实体关系。我们的数据库设置现在已经准备好了,让我们继续创建Hibernate多对多映射项目。
Hibernate多对多映射项目结构
在Eclipse或您最喜欢的IDE中创建一个maven项目,下图显示了应用程序中的结构和不同组件。我们将首先研究基于XML的映射实现,然后转向使用JPA注释。
Hibernate Maven依赖
最终的pom.xml包含最新版本4.3.5的Hibernate依赖项 和MySQL驱动程序依赖项** 。pom.xml
1<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
2 xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>com.journaldev.hibernate</groupId>
5 <artifactId>HibernateManyToManyMapping</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7
8 <dependencies>
9 <dependency>
10 <groupId>org.hibernate</groupId>
11 <artifactId>hibernate-core</artifactId>
12 <version>4.3.5.Final</version>
13 </dependency>
14 <dependency>
15 <groupId>mysql</groupId>
16 <artifactId>mysql-connector-java</artifactId>
17 <version>5.0.5</version>
18 </dependency>
19 </dependencies>
20
21</project>
休眠多对多XML配置模型类
Cart.java
1package com.journaldev.hibernate.model;
2
3import java.util.Set;
4
5public class Cart {
6
7 private long id;
8 private double total;
9
10 private Set<Item> items;
11
12 public double getTotal() {
13 return total;
14 }
15
16 public void setTotal(double total) {
17 this.total = total;
18 }
19
20 public long getId() {
21 return id;
22 }
23
24 public void setId(long id) {
25 this.id = id;
26 }
27
28 public Set<Item> getItems() {
29 return items;
30 }
31
32 public void setItems(Set<Item> items) {
33 this.items = items;
34 }
35
36}
‘tem.java’,你知道的。
1package com.journaldev.hibernate.model;
2
3import java.util.Set;
4
5public class Item {
6
7 private long id;
8 private double price;
9 private String description;
10
11 private Set<Cart> carts;
12
13 public long getId() {
14 return id;
15 }
16
17 public void setId(long id) {
18 this.id = id;
19 }
20
21 public double getPrice() {
22 return price;
23 }
24
25 public void setPrice(double price) {
26 this.price = price;
27 }
28
29 public String getDescription() {
30 return description;
31 }
32
33 public void setDescription(String description) {
34 this.description = description;
35 }
36
37 public Set<Cart> getCarts() {
38 return carts;
39 }
40
41 public void setCarts(Set<Cart> carts) {
42 this.carts = carts;
43 }
44}
请注意,购物车有一组商品,而商品有一套购物车,这样我们就实现了双向关联。这意味着我们可以将其配置为在保存购物车时保存项目,反之亦然。对于单向映射,通常我们都会在其中设置一个模型类。我们将使用注释进行单向映射。
Hibernate多对多映射XML配置
让我们为购物车和商品创建Hibernate多对多映射XML配置文件。我们将实现双向多对多映射。cart.hbm.xml
1<?xml version="1.0"?>
2<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
3 "https://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
4
5<hibernate-mapping package="com.journaldev.hibernate.model">
6 <class name="Cart" table="CART">
7 <id name="id" type="long">
8 <column name="cart_id" />
9 <generator class="identity" />
10 </id>
11 <property name="total" type="double" column="cart_total" />
12
13 <set name="items" table="CART_ITEMS" fetch="select" cascade="all">
14 <key column="cart_id" />
15 <many-to-many class="Item" column="item_id" />
16 </set>
17 </class>
18
19</hibernate-mapping>
请注意,项目集映射到CART_ITEMS表。由于Cart是主要对象,因此cart_id是键,而多对多
映射使用Item类item_id列。item.hbm.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
3"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
4
5<hibernate-mapping package="com.journaldev.hibernate.model">
6
7 <class name="Item" table="ITEM">
8 <id name="id" type="long">
9 <column name="item_id" />
10 <generator class="identity" />
11 </id>
12 <property name="description" type="string" column="item_desc" />
13
14 <property name="price" type="double" column="item_price" />
15
16 <set name="carts" table="CART_ITEMS" fetch="select" cascade="all">
17 <key column="item_id" />
18 <many-to-many class="Cart" column="cart_id" />
19 </set>
20
21 </class>
22
23</hibernate-mapping>
从上面可以看到,映射与购物车映射配置非常相似。
基于XML的多对多映射的Hibernate配置
我们的Hibernate配置文件如下所示。hibernate.cfg.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE hibernate-configuration PUBLIC
3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
4 "https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
5<hibernate-configuration>
6 <session-factory>
7 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
8 <property name="hibernate.connection.password">pankaj123</property>
9 <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
10 <property name="hibernate.connection.username">pankaj</property>
11 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
12
13 <property name="hibernate.current_session_context_class">thread</property>
14 <property name="hibernate.show_sql">true</property>
15
16 <mapping resource="cart.hbm.xml" />
17 <mapping resource="item.hbm.xml" />
18 </session-factory>
19</hibernate-configuration>
基于XML映射的Hibernate SessionFactory实用程序类
‘HibernateUtil.java’
1package com.journaldev.hibernate.util;
2
3import org.hibernate.SessionFactory;
4import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
5import org.hibernate.cfg.Configuration;
6import org.hibernate.service.ServiceRegistry;
7
8public class HibernateUtil {
9
10 private static SessionFactory sessionFactory;
11
12 private static SessionFactory buildSessionFactory() {
13 try {
14 // Create the SessionFactory from hibernate.cfg.xml
15 Configuration configuration = new Configuration();
16 configuration.configure("hibernate.cfg.xml");
17 System.out.println("Hibernate Configuration loaded");
18
19 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
20 .applySettings(configuration.getProperties()).build();
21 System.out.println("Hibernate serviceRegistry created");
22
23 SessionFactory sessionFactory = configuration
24 .buildSessionFactory(serviceRegistry);
25
26 return sessionFactory;
27 } catch (Throwable ex) {
28 System.err.println("Initial SessionFactory creation failed." + ex);
29 ex.printStackTrace();
30 throw new ExceptionInInitializerError(ex);
31 }
32 }
33
34 public static SessionFactory getSessionFactory() {
35 if (sessionFactory == null)
36 sessionFactory = buildSessionFactory();
37 return sessionFactory;
38 }
39
40}
这是一个简单的实用程序类,用作SessionFactory
的工厂。
Hibernate多对多映射XML配置测试方案
我们的Hibernate多对多映射设置已经准备好了,让我们来测试一下。我们将编写两个程序,一个是保存购物车,并看到Items和Cart_Items信息也被保存。另一个用于保存物品数据并检查相应的Cart和Cart_Items是否已保存。HibernateManyToManyMain.java
1package com.journaldev.hibernate.main;
2
3import java.util.HashSet;
4import java.util.Set;
5
6import org.hibernate.Session;
7import org.hibernate.SessionFactory;
8import org.hibernate.Transaction;
9
10import com.journaldev.hibernate.model.Cart;
11import com.journaldev.hibernate.model.Item;
12import com.journaldev.hibernate.util.HibernateUtil;
13
14public class HibernateManyToManyMain {
15
16 //Saving many-to-many where Cart is primary
17 public static void main(String[] args) {
18
19 Item iphone = new Item();
20 iphone.setPrice(100); iphone.setDescription("iPhone");
21
22 Item ipod = new Item();
23 ipod.setPrice(50); ipod.setDescription("iPod");
24
25 Set<Item> items = new HashSet<Item>();
26 items.add(iphone); items.add(ipod);
27
28 Cart cart = new Cart();
29 cart.setItems(items);
30 cart.setTotal(150);
31
32 Cart cart1 = new Cart();
33 Set<Item> items1 = new HashSet<Item>();
34 items1.add(iphone);
35 cart1.setItems(items1);
36 cart1.setTotal(100);
37
38 SessionFactory sessionFactory = null;
39 try{
40 sessionFactory = HibernateUtil.getSessionFactory();
41 Session session = sessionFactory.getCurrentSession();
42 Transaction tx = session.beginTransaction();
43 session.save(cart);
44 session.save(cart1);
45 System.out.println("Before committing transaction");
46 tx.commit();
47 sessionFactory.close();
48
49 System.out.println("Cart ID="+cart.getId());
50 System.out.println("Cart1 ID="+cart1.getId());
51 System.out.println("Item1 ID="+iphone.getId());
52 System.out.println("Item2 ID="+ipod.getId());
53
54 }catch(Exception e){
55 e.printStackTrace();
56 }finally{
57 if(sessionFactory != null && !sessionFactory.isClosed()) sessionFactory.close();
58 }
59
60 }
61
62}
当我们执行上面的Hibernate多对多映射示例程序时,我们得到以下输出。
1Hibernate Configuration loaded
2Hibernate serviceRegistry created
3Hibernate: insert into CART (cart_total) values (?)
4Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
5Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
6Hibernate: insert into CART (cart_total) values (?)
7Before committing transaction
8Hibernate: insert into CART_ITEMS (cart_id, item_id) values (?, ?)
9Hibernate: insert into CART_ITEMS (cart_id, item_id) values (?, ?)
10Hibernate: insert into CART_ITEMS (cart_id, item_id) values (?, ?)
11Cart ID=1
12Cart1 ID=2
13Item1 ID=1
14Item2 ID=2
请注意,一旦通过第一个购物车保存了物品数据,就会生成Item_id,在保存第二个购物车时,不会再次保存它。另一个需要注意的要点是,当我们提交事务时,会保存多对多连接表数据。这样做是为了在我们选择回滚事务时获得更好的性能。HibernateBiDirectionalManyToManyMain.java
1package com.journaldev.hibernate.main;
2
3import java.util.HashSet;
4import java.util.Set;
5
6import org.hibernate.Session;
7import org.hibernate.SessionFactory;
8import org.hibernate.Transaction;
9
10import com.journaldev.hibernate.model.Cart;
11import com.journaldev.hibernate.model.Item;
12import com.journaldev.hibernate.util.HibernateUtil;
13
14public class HibernateBiDirectionalManyToManyMain {
15
16 //Saving many-to-many where Item is primary
17 public static void main(String[] args) {
18
19 Item iphone = new Item();
20 iphone.setPrice(100); iphone.setDescription("iPhone");
21
22 Item ipod = new Item();
23 ipod.setPrice(50); ipod.setDescription("iPod");
24
25 Cart cart = new Cart();
26 cart.setTotal(150);
27
28 Cart cart1 = new Cart();
29 cart1.setTotal(100);
30
31 Set<Cart> cartSet = new HashSet<Cart>();
32 cartSet.add(cart);cartSet.add(cart1);
33
34 Set<Cart> cartSet1 = new HashSet<Cart>();
35 cartSet1.add(cart);
36
37 iphone.setCarts(cartSet1);
38 ipod.setCarts(cartSet);
39
40 SessionFactory sessionFactory = null;
41 try{
42 sessionFactory = HibernateUtil.getSessionFactory();
43 Session session = sessionFactory.getCurrentSession();
44 Transaction tx = session.beginTransaction();
45 session.save(iphone);
46 session.save(ipod);
47 tx.commit();
48 sessionFactory.close();
49
50 System.out.println("Cart ID="+cart.getId());
51 System.out.println("Cart1 ID="+cart1.getId());
52 System.out.println("Item1 ID="+iphone.getId());
53 System.out.println("Item2 ID="+ipod.getId());
54
55 }catch(Exception e){
56 e.printStackTrace();
57 }finally{
58 if(sessionFactory != null && !sessionFactory.isClosed()) sessionFactory.close();
59 }
60
61 }
62
63}
上述程序的输出是:
1Hibernate Configuration loaded
2Hibernate serviceRegistry created
3Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
4Hibernate: insert into CART (cart_total) values (?)
5Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
6Hibernate: insert into CART (cart_total) values (?)
7Hibernate: insert into CART_ITEMS (item_id, cart_id) values (?, ?)
8Hibernate: insert into CART_ITEMS (item_id, cart_id) values (?, ?)
9Hibernate: insert into CART_ITEMS (item_id, cart_id) values (?, ?)
10Cart ID=3
11Cart1 ID=4
12Item1 ID=3
13Item2 ID=4
您可以很容易地将其与以前的测试程序相关联,因为我们已经配置了双向映射,我们可以保存物品或购物车,映射的数据将自动保存。
休眠多对多映射注释
现在我们已经看到了如何使用hibernate xml配置来配置 多对多 映射,让我们看一个通过注释实现它的例子。我们将使用JPA注释实现单向多对多映射。
Hibernate配置XML文件
我们的基于注释的Hibernate配置文件如下所示。休眠-注解.cfg.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE hibernate-configuration PUBLIC
3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
4 "https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
5<hibernate-configuration>
6 <session-factory>
7 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
8 <property name="hibernate.connection.password">pankaj123</property>
9 <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
10 <property name="hibernate.connection.username">pankaj</property>
11 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
12
13 <property name="hibernate.current_session_context_class">thread</property>
14 <property name="hibernate.show_sql">true</property>
15
16 <mapping class="com.journaldev.hibernate.model.Cart1" />
17 <mapping class="com.journaldev.hibernate.model.Item1" />
18 </session-factory>
19</hibernate-configuration>
Hibernate SessionFactory工具类
我们用来创建SessionFactory的工具类如下所示。HibernateAnnotationUtil.java
1package com.journaldev.hibernate.util;
2
3import org.hibernate.SessionFactory;
4import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
5import org.hibernate.cfg.Configuration;
6import org.hibernate.service.ServiceRegistry;
7
8public class HibernateAnnotationUtil {
9
10 private static SessionFactory sessionFactory;
11
12 private static SessionFactory buildSessionFactory() {
13 try {
14 // Create the SessionFactory from hibernate-annotation.cfg.xml
15 Configuration configuration = new Configuration();
16 configuration.configure("hibernate-annotation.cfg.xml");
17 System.out.println("Hibernate Annotation Configuration loaded");
18
19 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
20 System.out.println("Hibernate Annotation serviceRegistry created");
21
22 SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
23
24 return sessionFactory;
25 }
26 catch (Throwable ex) {
27 System.err.println("Initial SessionFactory creation failed." + ex);
28 ex.printStackTrace();
29 throw new ExceptionInInitializerError(ex);
30 }
31 }
32
33 public static SessionFactory getSessionFactory() {
34 if(sessionFactory == null) sessionFactory = buildSessionFactory();
35 return sessionFactory;
36 }
37}
Hibernate多对多映射注释模型类
这是基于注释的映射最重要的部分,让我们首先看看Item表模型类,然后我们将研究Cart表模型类。项目1.java
1package com.journaldev.hibernate.model;
2
3import javax.persistence.Column;
4import javax.persistence.Entity;
5import javax.persistence.GeneratedValue;
6import javax.persistence.GenerationType;
7import javax.persistence.Id;
8import javax.persistence.Table;
9
10@Entity
11@Table(name="ITEM")
12public class Item1 {
13
14 @Id
15 @Column(name="item_id")
16 @GeneratedValue(strategy=GenerationType.IDENTITY)
17 private long id;
18
19 @Column(name="item_price")
20 private double price;
21
22 @Column(name="item_desc")
23 private String description;
24
25// Getter Setter methods
26}
Item1类看起来很简单,这里没有关系映射。Cart1.java
1package com.journaldev.hibernate.model;
2
3import java.util.Set;
4
5import javax.persistence.CascadeType;
6import javax.persistence.Column;
7import javax.persistence.Entity;
8import javax.persistence.GeneratedValue;
9import javax.persistence.GenerationType;
10import javax.persistence.Id;
11import javax.persistence.JoinColumn;
12import javax.persistence.JoinTable;
13import javax.persistence.ManyToMany;
14import javax.persistence.Table;
15
16@Entity
17@Table(name = "CART")
18public class Cart1 {
19
20 @Id
21 @Column(name = "cart_id")
22 @GeneratedValue(strategy = GenerationType.IDENTITY)
23 private long id;
24
25 @Column(name = "cart_total")
26 private double total;
27
28 @ManyToMany(targetEntity = Item1.class, cascade = { CascadeType.ALL })
29 @JoinTable(name = "CART_ITEMS",
30 joinColumns = { @JoinColumn(name = "cart_id") },
31 inverseJoinColumns = { @JoinColumn(name = "item_id") })
32 private Set<Item1> items;
33
34//Getter Setter methods
35}
这里最重要的部分是使用ManyToMany
注释和JoinTable
注释,其中我们提供用于多对多映射的表名和列。
Hibernate多对多注释映射测试程序
下面是一个简单的测试程序,用于我们的基于Hibernate多对多映射注释的配置。HibernateManyToManyAnnotationMain.java
1package com.journaldev.hibernate.main;
2
3import java.util.HashSet;
4import java.util.Set;
5
6import org.hibernate.Session;
7import org.hibernate.SessionFactory;
8import org.hibernate.Transaction;
9
10import com.journaldev.hibernate.model.Cart1;
11import com.journaldev.hibernate.model.Item1;
12import com.journaldev.hibernate.util.HibernateAnnotationUtil;
13
14public class HibernateManyToManyAnnotationMain {
15
16 public static void main(String[] args) {
17 Item1 item1 = new Item1();
18 item1.setDescription("samsung"); item1.setPrice(300);
19 Item1 item2 = new Item1();
20 item2.setDescription("nokia"); item2.setPrice(200);
21 Cart1 cart = new Cart1();
22 cart.setTotal(500);
23 Set<Item1> items = new HashSet<Item1>();
24 items.add(item1); items.add(item2);
25 cart.setItems(items);
26
27 SessionFactory sessionFactory = null;
28 try{
29 sessionFactory = HibernateAnnotationUtil.getSessionFactory();
30 Session session = sessionFactory.getCurrentSession();
31 Transaction tx = session.beginTransaction();
32 session.save(cart);
33 System.out.println("Before committing transaction");
34 tx.commit();
35 sessionFactory.close();
36
37 System.out.println("Cart ID="+cart.getId());
38 System.out.println("Item1 ID="+item1.getId());
39 System.out.println("Item2 ID="+item2.getId());
40
41 }catch(Exception e){
42 e.printStackTrace();
43 }finally{
44 if(sessionFactory != null && !sessionFactory.isClosed()) sessionFactory.close();
45 }
46 }
47
48}
当我们执行上面的程序时,它会产生以下输出。
1Hibernate Annotation Configuration loaded
2Hibernate Annotation serviceRegistry created
3Hibernate: insert into CART (cart_total) values (?)
4Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
5Hibernate: insert into ITEM (item_desc, item_price) values (?, ?)
6Before committing transaction
7Hibernate: insert into CART_ITEMS (cart_id, item_id) values (?, ?)
8Hibernate: insert into CART_ITEMS (cart_id, item_id) values (?, ?)
9Cart ID=5
10Item1 ID=6
11Item2 ID=5
显然,保存购物车也就是将数据保存到Item和Cart_Items表中。如果只保存商品信息,您将注意到没有保存Cart和Cart_Items数据。这就是Hibernate多对多映射示例教程,您可以从下面的链接下载样例项目并尝试了解更多信息。