今天,我们将研究Hibernate中的一对一映射。我们将研究使用注释和XML配置的Hibernate一对一映射示例。
Hibernate中的一对一映射
大多数时候,数据库表都是相互关联的。有多种形式的关联--一对一 、** 一对多** 和** 多对多** 是广义的。这些映射又可进一步分为单向映射和双向映射。今天,我们将介绍如何使用** XML配置** 和** 注释配置** 来实现** Hibernate一对一映射** 。
Hibernate一对一映射示例数据库设置
首先,我们需要在数据库表中设置一对一映射。我们将为我们的示例创建两个表-Transaction和Customer。这两个表都将有一对一的映射。Transaction将作为主表,我们将在Customer表中使用外键 进行一对一映射。我提供MySQL脚本,这是我在本教程中使用的数据库。如果您正在使用任何其他数据库,请确保相应地更改脚本。
1-- Create Transaction Table
2CREATE TABLE `Transaction` (
3 `txn_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
4 `txn_date` date NOT NULL,
5 `txn_total` decimal(10,0) NOT NULL,
6 PRIMARY KEY (`txn_id`)
7) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
8
9-- Create Customer table
10CREATE TABLE `Customer` (
11 `txn_id` int(11) unsigned NOT NULL,
12 `cust_name` varchar(20) NOT NULL DEFAULT '',
13 `cust_email` varchar(20) DEFAULT NULL,
14 `cust_address` varchar(50) NOT NULL DEFAULT '',
15 PRIMARY KEY (`txn_id`),
16 CONSTRAINT `customer_ibfk_1` FOREIGN KEY (`txn_id`) REFERENCES `Transaction` (`txn_id`)
17) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表之间一对一映射的实体关系图(ERD)如下图所示。我们的数据库设置已经准备好了,现在让我们转移到Hibernate One to One示例项目上。
Hibernate一对一映射示例项目结构
在您的Java IDE中创建一个简单的Maven项目,我使用的是Eclipse。我们最终的项目结构将如下图所示。首先我们将研究基于XML语言的Hibernate一对一映射示例,然后我们将使用注释实现相同的事情。
Hibernate Maven依赖
我们最终的pom.xml文件如下所示。
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>HibernateOneToOneMapping</artifactId>
5 <version>0.0.1-SNAPSHOT</version>
6 <dependencies>
7 <dependency>
8 <groupId>org.hibernate</groupId>
9 <artifactId>hibernate-core</artifactId>
10 <version>4.3.5.Final</version>
11 </dependency>
12 <dependency>
13 <groupId>mysql</groupId>
14 <artifactId>mysql-connector-java</artifactId>
15 <version>5.0.5</version>
16 </dependency>
17 </dependencies>
18</project>
依赖项只适用于Hibernate和MySQL Java驱动程序。请注意,我使用的是Hibernate最新版本4.3.5最终 和基于我的MySQL数据库服务器版本(5.0.5)的MySQL Java驱动程序。Hibernate4使用JBoss日志记录,它会自动作为可传递依赖项导入。您可以在项目的Maven依赖项中确认它。如果您使用的是Hibernate较早的版本,则可能需要添加slf4j依赖项。
Hibernate一对一映射模型类
用于Hibernate一对一映射以反映数据库表的模型类如下所示。
1package com.journaldev.hibernate.model;
2
3import java.util.Date;
4
5public class Txn {
6
7 private long id;
8 private Date date;
9 private double total;
10 private Customer customer;
11
12 @Override
13 public String toString(){
14 return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress();
15 }
16 public long getId() {
17 return id;
18 }
19 public void setId(long id) {
20 this.id = id;
21 }
22 public Date getDate() {
23 return date;
24 }
25 public void setDate(Date date) {
26 this.date = date;
27 }
28 public double getTotal() {
29 return total;
30 }
31 public void setTotal(double total) {
32 this.total = total;
33 }
34 public Customer getCustomer() {
35 return customer;
36 }
37 public void setCustomer(Customer customer) {
38 this.customer = customer;
39 }
40
41}
1package com.journaldev.hibernate.model;
2
3public class Customer {
4
5 private long id;
6 private String name;
7 private String email;
8 private String address;
9
10 private Txn txn;
11
12 public long getId() {
13 return id;
14 }
15 public void setId(long id) {
16 this.id = id;
17 }
18 public String getName() {
19 return name;
20 }
21 public void setName(String name) {
22 this.name = name;
23 }
24 public String getEmail() {
25 return email;
26 }
27 public void setEmail(String email) {
28 this.email = email;
29 }
30 public String getAddress() {
31 return address;
32 }
33 public void setAddress(String address) {
34 this.address = address;
35 }
36 public Txn getTxn() {
37 return txn;
38 }
39 public void setTxn(Txn txn) {
40 this.txn = txn;
41 }
42
43}
因为我们使用基于XML的配置进行映射,所以上面的模型类是简单的POJO类或带有getter-setter方法的Java Bean。我使用类名为Txn
是为了避免混淆,因为Hibernate API有一个类名为Transaction
。
Hibernate一对一映射配置
让我们为TXN和Customer表创建Hibernate一对一映射配置文件。txn.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<hibernate-mapping>
5 <class name="com.journaldev.hibernate.model.Txn" table="TRANSACTION" >
6 <id name="id" type="long">
7 <column name="txn_id" />
8 <generator class="identity" />
9 </id>
10 <property name="date" type="date">
11 <column name="txn_date" />
12 </property>
13 <property name="total" type="double">
14 <column name="txn_total" />
15 </property>
16 <one-to-one name="customer" class="com.journaldev.hibernate.model.Customer"
17 cascade="save-update" />
18 </class>
19
20</hibernate-mapping>
上面要注意的重要一点是用于customer属性的hibernateone-to-one
元素。customer.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<hibernate-mapping>
5
6 <class name="com.journaldev.hibernate.model.Customer" table="CUSTOMER">
7 <id name="id" type="long">
8 <column name="txn_id" />
9 <generator class="foreign">
10 <param name="property">txn</param>
11 </generator>
12 </id>
13 <one-to-one name="txn" class="com.journaldev.hibernate.model.Txn"
14 constrained="true"></one-to-one>
15
16 <property name="name" type="string">
17 <column name="cust_name"></column>
18 </property>
19 <property name="email" type="string">
20 <column name="cust_email"></column>
21 </property>
22 <property name="address" type="string">
23 <column name="cust_address"></column>
24 </property>
25 </class>
26
27</hibernate-mapping>
生成器类=foreign
是Hibernate实现** 外键** 的重要部分。
休眠配置文件
下面是基于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="txn.hbm.xml"/>
17 <mapping resource="customer.hbm.xml"/>
18 </session-factory>
19</hibernate-configuration>
Hibernate配置文件很简单,它有数据库连接属性和Hibernate映射资源。
休眠SessionFactory实用程序
下面是用于创建Hibernate SessionFactory实例的实用程序类。
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的一对一映射示例测试程序中,首先我们将创建TXN对象并保存。一旦它被保存到数据库中,我们将使用生成的id来检索TXN对象并打印它。
1package com.journaldev.hibernate.main;
2
3import java.util.Date;
4
5import org.hibernate.Session;
6import org.hibernate.SessionFactory;
7import org.hibernate.Transaction;
8
9import com.journaldev.hibernate.model.Customer;
10import com.journaldev.hibernate.model.Txn;
11import com.journaldev.hibernate.util.HibernateUtil;
12
13public class HibernateOneToOneMain {
14
15 public static void main(String[] args) {
16
17 Txn txn = buildDemoTransaction();
18
19 SessionFactory sessionFactory = null;
20 Session session = null;
21 Transaction tx = null;
22 try{
23 //Get Session
24 sessionFactory = HibernateUtil.getSessionFactory();
25 session = sessionFactory.getCurrentSession();
26 System.out.println("Session created");
27 //start transaction
28 tx = session.beginTransaction();
29 //Save the Model object
30 session.save(txn);
31 //Commit transaction
32 tx.commit();
33 System.out.println("Transaction ID="+txn.getId());
34
35 //Get Saved Trasaction Data
36 printTransactionData(txn.getId(), sessionFactory);
37
38 }catch(Exception e){
39 System.out.println("Exception occured. "+e.getMessage());
40 e.printStackTrace();
41 }finally{
42 if(!sessionFactory.isClosed()){
43 System.out.println("Closing SessionFactory");
44 sessionFactory.close();
45 }
46 }
47 }
48
49 private static void printTransactionData(long id, SessionFactory sessionFactory) {
50 Session session = null;
51 Transaction tx = null;
52 try{
53 //Get Session
54 sessionFactory = HibernateUtil.getSessionFactory();
55 session = sessionFactory.getCurrentSession();
56 //start transaction
57 tx = session.beginTransaction();
58 //Save the Model object
59 Txn txn = (Txn) session.get(Txn.class, id);
60 //Commit transaction
61 tx.commit();
62 System.out.println("Transaction Details=\n"+txn);
63
64 }catch(Exception e){
65 System.out.println("Exception occured. "+e.getMessage());
66 e.printStackTrace();
67 }
68 }
69
70 private static Txn buildDemoTransaction() {
71 Txn txn = new Txn();
72 txn.setDate(new Date());
73 txn.setTotal(100);
74
75 Customer cust = new Customer();
76 cust.setAddress("Bangalore, India");
77 cust.setEmail("[email protected]");
78 cust.setName("Pankaj Kumar");
79
80 txn.setCustomer(cust);
81
82 cust.setTxn(txn);
83 return txn;
84 }
85
86}
现在,当我们在Hibernate测试程序中运行一对一映射时,我们会得到以下输出。
1Hibernate Configuration loaded
2Hibernate serviceRegistry created
3Session created
4Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?)
5Hibernate: insert into CUSTOMER (cust_name, cust_email, cust_address, txn_id) values (?, ?, ?, ?)
6Transaction ID=19
7Hibernate: select txn0_.txn_id as txn_id1_1_0_, txn0_.txn_date as txn_date2_1_0_, txn0_.txn_total as txn_tota3_1_0_,
8customer1_.txn_id as txn_id1_0_1_, customer1_.cust_name as cust_nam2_0_1_, customer1_.cust_email as cust_ema3_0_1_,
9customer1_.cust_address as cust_add4_0_1_ from TRANSACTION txn0_ left outer join CUSTOMER customer1_ on
10txn0_.txn_id=customer1_.txn_id where txn0_.txn_id=?
11Transaction Details=
1219, 100.0, Pankaj Kumar, pankaj@gmail.com, Bangalore, India
13Closing SessionFactory
正如您所看到的,它工作得很好,并且我们能够使用事务ID从两个表中检索数据。检查Hibernate在内部使用的SQL以获取数据,它使用联接从两个表中获取数据。
Hibernate一对一映射注释
在上一节中,我们看到了如何使用基于XML的配置来实现Hibernate的一对一映射,现在让我们看看如何使用JPA和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.Txn1"/>
17 <mapping class="com.journaldev.hibernate.model.Customer1"/>
18 </session-factory>
19</hibernate-configuration>
Hibernate配置很简单,您可以看到我有两个模型类,我们将在注释中使用它们--Txn1
和Customer1
。
Hibernate一对一映射注释示例模型类
对于Hibernate一对一映射注释配置,模型类是最重要的部分。让我们来看看我们的模型类是什么样子。
1package com.journaldev.hibernate.model;
2
3import java.util.Date;
4
5import javax.persistence.Column;
6import javax.persistence.Entity;
7import javax.persistence.GeneratedValue;
8import javax.persistence.GenerationType;
9import javax.persistence.Id;
10import javax.persistence.OneToOne;
11import javax.persistence.Table;
12
13import org.hibernate.annotations.Cascade;
14
15@Entity
16@Table(name="TRANSACTION")
17public class Txn1 {
18
19 @Id
20 @GeneratedValue(strategy=GenerationType.IDENTITY)
21 @Column(name="txn_id")
22 private long id;
23
24 @Column(name="txn_date")
25 private Date date;
26
27 @Column(name="txn_total")
28 private double total;
29
30 @OneToOne(mappedBy="txn")
31 @Cascade(value=org.hibernate.annotations.CascadeType.SAVE_UPDATE)
32 private Customer1 customer;
33
34 @Override
35 public String toString(){
36 return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress();
37 }
38
39 //Getter-Setter methods, omitted for clarity
40}
请注意,大多数注释来自Java持久性API,因为Hibernate提供了它的实现。但是,对于级联,我们将需要使用Hibernate注释org.hibernate.nottations.Cascade
和枚举org.hibernate.nottations.CascadeType
。
1package com.journaldev.hibernate.model;
2
3import javax.persistence.Column;
4import javax.persistence.Entity;
5import javax.persistence.GeneratedValue;
6import javax.persistence.Id;
7import javax.persistence.OneToOne;
8import javax.persistence.PrimaryKeyJoinColumn;
9import javax.persistence.Table;
10
11import org.hibernate.annotations.GenericGenerator;
12import org.hibernate.annotations.Parameter;
13
14@Entity
15@Table(name="CUSTOMER")
16public class Customer1 {
17
18 @Id
19 @Column(name="txn_id", unique=true, nullable=false)
20 @GeneratedValue(generator="gen")
21 @GenericGenerator(name="gen", strategy="foreign", parameters={@Parameter(name="property", value="txn")})
22 private long id;
23
24 @Column(name="cust_name")
25 private String name;
26
27 @Column(name="cust_email")
28 private String email;
29
30 @Column(name="cust_address")
31 private String address;
32
33 @OneToOne
34 @PrimaryKeyJoinColumn
35 private Txn1 txn;
36
37 //Getter-Setter methods
38}
请注意,我们需要@GenericGenerator
,以便从TXN使用id,而不是生成它。
Hibernate SessionFactory实用程序类
创建SessionFactory独立于我们提供Hibernate映射的方式。我们用于创建SessionFactory的实用程序类如下所示。
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一对一映射注释示例测试程序
下面是一个简单的测试程序,用于我们的hibernate一对一映射注释示例。
1package com.journaldev.hibernate.main;
2
3import java.util.Date;
4
5import org.hibernate.Session;
6import org.hibernate.SessionFactory;
7import org.hibernate.Transaction;
8
9import com.journaldev.hibernate.model.Customer1;
10import com.journaldev.hibernate.model.Txn1;
11import com.journaldev.hibernate.util.HibernateAnnotationUtil;
12
13public class HibernateOneToOneAnnotationMain {
14
15 public static void main(String[] args) {
16
17 Txn1 txn = buildDemoTransaction();
18
19 SessionFactory sessionFactory = null;
20 Session session = null;
21 Transaction tx = null;
22 try{
23 //Get Session
24 sessionFactory = HibernateAnnotationUtil.getSessionFactory();
25 session = sessionFactory.getCurrentSession();
26 System.out.println("Session created using annotations configuration");
27 //start transaction
28 tx = session.beginTransaction();
29 //Save the Model object
30 session.save(txn);
31 //Commit transaction
32 tx.commit();
33 System.out.println("Annotation Example. Transaction ID="+txn.getId());
34
35 //Get Saved Trasaction Data
36 printTransactionData(txn.getId(), sessionFactory);
37 }catch(Exception e){
38 System.out.println("Exception occured. "+e.getMessage());
39 e.printStackTrace();
40 }finally{
41 if(sessionFactory != null && !sessionFactory.isClosed()){
42 System.out.println("Closing SessionFactory");
43 sessionFactory.close();
44 }
45 }
46 }
47
48 private static void printTransactionData(long id, SessionFactory sessionFactory) {
49 Session session = null;
50 Transaction tx = null;
51 try{
52 //Get Session
53 sessionFactory = HibernateAnnotationUtil.getSessionFactory();
54 session = sessionFactory.getCurrentSession();
55 //start transaction
56 tx = session.beginTransaction();
57 //Save the Model object
58 Txn1 txn = (Txn1) session.get(Txn1.class, id);
59 //Commit transaction
60 tx.commit();
61 System.out.println("Annotation Example. Transaction Details=\n"+txn);
62
63 }catch(Exception e){
64 System.out.println("Exception occured. "+e.getMessage());
65 e.printStackTrace();
66 }
67 }
68
69 private static Txn1 buildDemoTransaction() {
70 Txn1 txn = new Txn1();
71 txn.setDate(new Date());
72 txn.setTotal(100);
73
74 Customer1 cust = new Customer1();
75 cust.setAddress("San Jose, USA");
76 cust.setEmail("[email protected]");
77 cust.setName("Pankaj Kr");
78
79 txn.setCustomer(cust);
80
81 cust.setTxn(txn);
82 return txn;
83 }
84
85}
这是我们执行上述程序时的输出片段。
1Hibernate Annotation Configuration loaded
2Hibernate Annotation serviceRegistry created
3Session created using annotations configuration
4Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?)
5Hibernate: insert into CUSTOMER (cust_address, cust_email, cust_name, txn_id) values (?, ?, ?, ?)
6Annotation Example. Transaction ID=20
7Hibernate: select txn1x0_.txn_id as txn_id1_1_0_, txn1x0_.txn_date as txn_date2_1_0_, txn1x0_.txn_total as txn_tota3_1_0_,
8customer1x1_.txn_id as txn_id1_0_1_, customer1x1_.cust_address as cust_add2_0_1_, customer1x1_.cust_email as cust_ema3_0_1_,
9customer1x1_.cust_name as cust_nam4_0_1_ from TRANSACTION txn1x0_ left outer join CUSTOMER customer1x1_ on
10txn1x0_.txn_id=customer1x1_.txn_id where txn1x0_.txn_id=?
11Annotation Example. Transaction Details=
1220, 100.0, Pankaj Kr, pankaj@yahoo.com, San Jose, USA
13Closing SessionFactory
请注意,该输出类似于基于Hibernate一对一XML的配置。这就是Hibernate一对一映射的例子,你可以从下面的链接下载最终项目并尝试了解更多。