Hibernate 一对多映射示例注释

今天,我们将研究Hibernate中的一对多映射。我们将研究使用注释和XML配置的Hibernate一对多映射示例。

Hibernate中的一对多映射

Hibernate中的一对多映射,Hibernate一对多映射,Hibernate映射示例,Hibernate一对多映射注释example简而言之,一对多映射是指一张表中的一行可以映射到另一张表中的多行。例如,设想一个购物车系统,其中我们有另一张桌子来存放物品。一个购物车可以有多个项目,所以这里有一对多映射。我们将使用购物车场景作为Hibernate一对多映射示例。

Hibernate-数据库设置中的一对多映射

我们可以使用外键约束 进行一对多映射。下面是我们的CartItems表的数据库脚本。我是用MySQL数据库进行Hibernate一对多映射的例子。setup.sql

 1CREATE TABLE `Cart` (
 2  `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 3  `total` decimal(10,0) NOT NULL,
 4  `name` varchar(10) DEFAULT NULL,
 5  PRIMARY KEY (`cart_id`)
 6) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
 7
 8CREATE TABLE `Items` (
 9  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
10  `cart_id` int(11) unsigned NOT NULL,
11  `item_id` varchar(10) NOT NULL,
12  `item_total` decimal(10,0) NOT NULL,
13  `quantity` int(3) NOT NULL,
14  PRIMARY KEY (`id`),
15  KEY `cart_id` (`cart_id`),
16  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
17) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

下面是购物车和物品表的ER图。一对多映射,Hibernate中的一对多映射,Hibernate一对多映射Example我们的数据库设置已经准备好了,让我们继续创建Hibernate一对多映射示例项目。首先,我们将使用基于XML的配置,然后我们将使用Hibernate和JPA注释实现一对多映射。

Hibernate一对多映射项目结构

在Eclipse或您喜欢的IDE中创建一个简单的Maven项目,最终的项目结构将如下图所示。Hibernate一对多映射,Hibernate中的一对多映射,Hibernate一对多映射注释Example

Hibernate Maven依赖

最后的pom.xml文件包含Hibernate和MySQL驱动程序的依赖项。Hibernate使用JBoss日志记录,并自动添加为可传递依赖项。

 1<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 2  <modelVersion>4.0.0</modelVersion>
 3  <groupId>com.journaldev.hibernate</groupId>
 4  <artifactId>HibernateOneToManyMapping</artifactId>
 5  <version>0.0.1-SNAPSHOT</version>
 6
 7  <dependencies>
 8    <dependency>
 9    	<groupId>org.hibernate</groupId>
10    	<artifactId>hibernate-core</artifactId>
11    	<version>4.3.5.Final</version>
12    </dependency>
13    <dependency>
14    	<groupId>mysql</groupId>
15    	<artifactId>mysql-connector-java</artifactId>
16    	<version>5.0.5</version>
17    </dependency>
18  </dependencies>
19
20</project>

请注意,我使用的是最新的Hibernate版本4.3.5最终版 和基于我的数据库安装的MySQL驱动程序版本。

Hibernate一对多映射模型类

对于我们的表Cart和Items,我们有模型类来反映它们。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    private String name;
10    private Set<Items> items;
11    
12    public long getId() {
13    	return id;
14    }
15    public void setId(long id) {
16    	this.id = id;
17    }
18    public double getTotal() {
19    	return total;
20    }
21    public void setTotal(double total) {
22    	this.total = total;
23    }
24    public String getName() {
25    	return name;
26    }
27    public void setName(String name) {
28    	this.name = name;
29    }
30    public Set<Items> getItems() {
31    	return items;
32    }
33    public void setItems(Set<Items> items) {
34    	this.items = items;
35    }
36    
37}

我使用的是一组条目,因此每条记录都是唯一的。我们还可以在Hibernate中使用List或数组进行一对多映射。Items.java

 1package com.journaldev.hibernate.model;
 2
 3public class Items {
 4
 5    private long id;
 6    private String itemId;
 7    private double itemTotal;
 8    private int quantity;
 9    private Cart cart;
10    
11    //Hibernate requires no-args constructor
12    public Items(){}
13    
14    public Items(String itemId, double total, int qty, Cart c){
15    	this.itemId=itemId;
16    	this.itemTotal=total;
17    	this.quantity=qty;
18    	this.cart=c;
19    }
20    public String getItemId() {
21    	return itemId;
22    }
23    public void setItemId(String itemId) {
24    	this.itemId = itemId;
25    }
26    public double getItemTotal() {
27    	return itemTotal;
28    }
29    public void setItemTotal(double itemTotal) {
30    	this.itemTotal = itemTotal;
31    }
32    public int getQuantity() {
33    	return quantity;
34    }
35    public void setQuantity(int quantity) {
36    	this.quantity = quantity;
37    }
38    public Cart getCart() {
39    	return cart;
40    }
41    public void setCart(Cart cart) {
42    	this.cart = cart;
43    }
44    public long getId() {
45    	return id;
46    }
47    public void setId(long id) {
48    	this.id = id;
49    }
50    
51}

商品与购物车有多对一的关系,因此我们不需要拥有购物车对象的集合。

Hibernate SessionFactory实用类

我们有一个用于创建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().applySettings(configuration.getProperties()).build();
20        	System.out.println("Hibernate 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配置XML文件

我们的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 resource="cart.hbm.xml"/>
17        <mapping resource="items.hbm.xml"/>
18    </session-factory>
19</hibernate-configuration>

Hibernate一对多映射示例--XML配置

这是教程中最重要的部分,让我们来看看如何在Hibernate中映射Cart和Items类进行一对多映射。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">
12    		<column name="total" />
13    	</property>
14    	<property name="name" type="string">
15    		<column name="name" />
16    	</property>
17    	<set name="items" table="ITEMS" fetch="select">
18    		<key>
19    			<column name="cart_id" not-null="true"></column>
20    		</key>
21    		<one-to-many class="Items"/>
22    	</set>
23    </class>
24    
25</hibernate-mapping>

重要的部分是其中的set元素和one-to-many元素。请注意,我们提供了用于一对多映射的键,即cart_id.items.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="Items" table="ITEMS">
 8    	<id name="id" type="long">
 9    		<column name="id" />
10    		<generator class="identity" />
11    	</id>
12    	<property name="itemId" type="string">
13    		<column name="item_id"></column>
14    	</property>
15    	<property name="itemTotal" type="double">
16    		<column name="item_total"></column>
17    	</property>
18    	<property name="quantity" type="integer">
19    		<column name="quantity"></column>
20    	</property>
21    	
22    	<many-to-one name="cart" class="Cart">
23    		<column name="cart_id" not-null="true"></column>
24    	</many-to-one>
25    </class>
26
27</hibernate-mapping>

注意,从商品到购物车,这是一种多对一的关系。所以我们需要对购物车使用`多对一‘元素,并且我们提供了将与键映射的列名。因此,基于购物车Hibernate映射配置,它的密钥cart_id将用于映射。我们的使用XML映射的Hibernate一对多映射示例的项目已经准备好了,让我们编写一个测试程序并检查它是否工作得很好。

Hibernate一对多映射示例-测试程序

HibernateOneToManyMain.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.Items;
12import com.journaldev.hibernate.util.HibernateUtil;
13
14public class HibernateOneToManyMain {
15
16    public static void main(String[] args) {
17
18    	Cart cart = new Cart();
19    	cart.setName("MyCart");
20    	
21    	Items item1 = new Items("I1", 10, 1, cart);
22    	Items item2 = new Items("I2", 20, 2, cart);
23    	Set<Items> itemsSet = new HashSet<Items>();
24    	itemsSet.add(item1); itemsSet.add(item2);
25    	
26    	cart.setItems(itemsSet);
27    	cart.setTotal(10*1 + 20*2);
28    	
29    	SessionFactory sessionFactory = null;
30    	Session session = null;
31    	Transaction tx = null;
32    	try{
33    	//Get Session
34    	sessionFactory = HibernateUtil.getSessionFactory();
35    	session = sessionFactory.getCurrentSession();
36    	System.out.println("Session created");
37    	//start transaction
38    	tx = session.beginTransaction();
39    	
40    	//Save the Model objects
41    	session.save(cart);
42    	session.save(item1);
43    	session.save(item2);
44    	
45    	//Commit transaction
46    	tx.commit();
47    	System.out.println("Cart ID="+cart.getId());
48    	
49    	}catch(Exception e){
50    		System.out.println("Exception occured. "+e.getMessage());
51    		e.printStackTrace();
52    	}finally{
53    		if(!sessionFactory.isClosed()){
54    			System.out.println("Closing SessionFactory");
55    			sessionFactory.close();
56    		}
57    	}
58    }
59
60}

请注意,我们需要逐个保存Cart和Items对象。Hibernate将负责更新Items表中的外键。当我们执行上面的程序时,我们得到以下输出。

 1Hibernate Configuration loaded
 2Hibernate serviceRegistry created
 3Session created
 4Hibernate: insert into CART (total, name) values (?, ?)
 5Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
 6Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
 7Hibernate: update ITEMS set cart_id=? where id=?
 8Hibernate: update ITEMS set cart_id=? where id=?
 9Cart ID=6
10Closing SessionFactory

请注意,Hibernate正在使用Update查询来设置ITEMS表中的cart_id。

Hibernate一对多映射注释

既然我们已经了解了如何使用基于XML的配置在Hibernate中实现一对多映射,让我们来看看如何使用JPA注释来做同样的事情。

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 class="com.journaldev.hibernate.model.Cart1"/>
17        <mapping class="com.journaldev.hibernate.model.Items1"/>
18    </session-factory>
19</hibernate-configuration>

Hibernate SessionFactory实用程序类

SessionFactory实用类几乎一样,我们只需要使用新的hibernate配置文件。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一对多映射注释模型类

因为我们没有基于XML的映射文件,所以所有与映射相关的配置都将使用模型类中的JPA注释来完成。如果您理解基于XML的映射,它是非常简单和相似的。Cart1.java

 1package com.journaldev.hibernate.model;
 2
 3import java.util.Set;
 4
 5import javax.persistence.Column;
 6import javax.persistence.Entity;
 7import javax.persistence.GeneratedValue;
 8import javax.persistence.GenerationType;
 9import javax.persistence.Id;
10import javax.persistence.OneToMany;
11import javax.persistence.Table;
12
13@Entity
14@Table(name="CART")
15public class Cart1 {
16
17    @Id
18    @GeneratedValue(strategy=GenerationType.IDENTITY)
19    @Column(name="cart_id")
20    private long id;
21    
22    @Column(name="total")
23    private double total;
24    
25    @Column(name="name")
26    private String name;
27    
28    @OneToMany(mappedBy="cart1")
29    private Set<Items1> items1;
30    
31// Getter Setter methods for properties
32}

需要注意的重要一点是OneToMany注释,其中mappedBy变量用于定义Items 1类中用于映射目的的属性。所以我们应该在Items 1类中有一个名为cart 1的属性。不要忘记包含所有的getter-setter方法。项目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.JoinColumn;
 9import javax.persistence.ManyToOne;
10import javax.persistence.Table;
11
12@Entity
13@Table(name="ITEMS")
14public class Items1 {
15
16    @Id
17    @GeneratedValue(strategy=GenerationType.IDENTITY)
18    @Column(name="id")
19    private long id;
20    
21    @Column(name="item_id")
22    private String itemId;
23    
24    @Column(name="item_total")
25    private double itemTotal;
26    
27    @Column(name="quantity")
28    private int quantity;
29    
30    @ManyToOne
31    @JoinColumn(name="cart_id", nullable=false)
32    private Cart1 cart1;
33    
34    //Hibernate requires no-args constructor
35    public Items1(){}
36    
37    public Items1(String itemId, double total, int qty, Cart1 c){
38    	this.itemId=itemId;
39    	this.itemTotal=total;
40    	this.quantity=qty;
41    	this.cart1=c;
42    }
43//Getter Setter methods
44}

上面类中最重要的一点是Cart1类变量上的ManyToOne注释和提供映射列名的JoinColumn注释。在Hibernate中使用模型类中的注释的一对多映射就是这样。将其与基于XML的配置进行比较,您会发现它们非常相似。让我们编写一个测试程序并执行它。

Hibernate一对多映射注释示例测试程序

我们的测试程序就像基于XML的配置一样,我们只是使用新的类来获取Hibernate会话并将模型对象保存到数据库中。HibernateOneToManyAnnotationMain.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.Items1;
12import com.journaldev.hibernate.util.HibernateAnnotationUtil;
13
14public class HibernateOneToManyAnnotationMain {
15
16    public static void main(String[] args) {
17
18    	Cart1 cart = new Cart1();
19    	cart.setName("MyCart1");
20    	
21    	Items1 item1 = new Items1("I10", 10, 1, cart);
22    	Items1 item2 = new Items1("I20", 20, 2, cart);
23    	Set<Items1> itemsSet = new HashSet<Items1>();
24    	itemsSet.add(item1); itemsSet.add(item2);
25    	
26    	cart.setItems1(itemsSet);
27    	cart.setTotal(10*1 + 20*2);
28    	
29    	SessionFactory sessionFactory = null;
30    	Session session = null;
31    	Transaction tx = null;
32    	try{
33    	//Get Session
34    	sessionFactory = HibernateAnnotationUtil.getSessionFactory();
35    	session = sessionFactory.getCurrentSession();
36    	System.out.println("Session created");
37    	//start transaction
38    	tx = session.beginTransaction();
39    	//Save the Model object
40    	session.save(cart);
41    	session.save(item1);
42    	session.save(item2);
43    	//Commit transaction
44    	tx.commit();
45    	System.out.println("Cart1 ID="+cart.getId());
46    	System.out.println("item1 ID="+item1.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
47    	System.out.println("item2 ID="+item2.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
48    	
49    	}catch(Exception e){
50    		System.out.println("Exception occured. "+e.getMessage());
51    		e.printStackTrace();
52    	}finally{
53    		if(!sessionFactory.isClosed()){
54    			System.out.println("Closing SessionFactory");
55    			sessionFactory.close();
56    		}
57    	}
58    }
59
60}

当我们执行上面的Hibernate一对多映射注释示例测试程序时,我们得到了以下输出。

 1Hibernate Annotation Configuration loaded
 2Hibernate Annotation serviceRegistry created
 3Session created
 4Hibernate: insert into CART (name, total) values (?, ?)
 5Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
 6Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
 7Cart1 ID=7
 8item1 ID=9, Foreign Key Cart ID=7
 9item2 ID=10, Foreign Key Cart ID=7
10Closing SessionFactory

这就是Hibernate一对多映射,从下面的链接下载样例项目,并做一些更多的实验。

下载Hibernate OneToMany映射Project

Published At
Categories with 技术
Tagged with
comments powered by Disqus