Hibernate 一对一映射示例注释
今天,我们将研究Hibernate中的一对一映射。
我们将研究使用注释和XML配置的Hibernate一对一映射示例。
Hibernate 中的一对一映射
在大多数情况下,数据库表是相互关联的。
关联的形式多种多样-一对一,一对多和多对多是广泛的关联。
这些可以进一步分为单向和双向映射。
今天,我们将研究使用XML配置以及注释配置实现Hibernate一对一映射。
Hibernate 一对一映射示例数据库设置
首先,我们需要在数据库表中设置一对一映射。
我们将为示例创建两个表-交易和客户。
这两个表将具有一对一的映射。
交易将是主表,我们将使用客户表中的外键进行一对一映射。
我正在提供MySQL脚本,也就是我用于本教程的数据库。
如果使用任何其他数据库,请确保相应地更改脚本。
-- Create Transaction Table CREATE TABLE `Transaction` ( `txn_id` int(11) unsigned NOT NULL AUTO_INCREMENT, `txn_date` date NOT NULL, `txn_total` decimal(10,0) NOT NULL, PRIMARY KEY (`txn_id`) ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; -- Create Customer table CREATE TABLE `Customer` ( `txn_id` int(11) unsigned NOT NULL, `cust_name` varchar(20) NOT NULL DEFAULT '', `cust_email` varchar(20) DEFAULT NULL, `cust_address` varchar(50) NOT NULL DEFAULT '', PRIMARY KEY (`txn_id`), CONSTRAINT `customer_ibfk_1` FOREIGN KEY (`txn_id`) REFERENCES `Transaction` (`txn_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表之间一对一映射的实体关系图(ERD)如下图所示。
我们的数据库设置已准备就绪,现在让我们继续进行Hibernate一对一示例项目。
Hibernate 一对一映射示例项目结构
我正在使用Eclipse在Java IDE中创建一个简单的Maven项目。
我们的最终项目结构将如下图所示。
首先,我们将研究基于XML的Hibernate一对一映射示例,然后我们将使用批注实现相同的事情。
Hibernate Maven依赖关系
我们最终的pom.xml文件如下所示。
<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"> <modelVersion>4.0.0</modelVersion> <groupId>com.theitroad.hibernate</groupId> <artifactId>HibernateOneToOneMapping</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.5.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.0.5</version> </dependency> </dependencies> </project>
依赖关系仅适用于Hibernate 和mysql Java驱动程序。
请注意,我正在使用基于我的MySQL数据库服务器版本(5.0.5)的Hibernate最新版本4.3.5.Final和MySQL Java驱动程序。
Hibernate 4使用JBoss日志记录,并自动将其作为传递依赖项导入。
您可以在项目的Maven依赖项中进行确认。
如果您使用的是较早版本的Hibernate,则可能必须添加slf4j依赖项。
Hibernate 一对一映射模型类
Hibernate一对一映射以反映数据库表的模型类如下所示。
package com.theitroad.hibernate.model; import java.util.Date; public class Txn { private long id; private Date date; private double total; private Customer customer; @Override public String toString(){ return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress(); } public long getId() { return id; } public void setId(long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public double getTotal() { return total; } public void setTotal(double total) { this.total = total; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
package com.theitroad.hibernate.model; public class Customer { private long id; private String name; private String email; private String address; private Txn txn; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Txn getTxn() { return txn; } public void setTxn(Txn txn) { this.txn = txn; } }
由于我们使用基于XML的配置进行映射,因此上述模型类是简单的POJO类或者具有getter-setter方法的Java Bean。
我将类名用作" Txn"以避免混淆,因为Hibernate API的类名为" Transaction"。
Hibernate 一对一映射配置
让我们为Txn和Customer表创建Hibernate 的一对一映射配置文件。
txn.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "https://hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.theitroad.hibernate.model.Txn" table="TRANSACTION" > <id name="id" type="long"> <column name="txn_id" <generator class="identity" </id> <property name="date" type="date"> <column name="txn_date" </property> <property name="total" type="double"> <column name="txn_total" </property> <one-to-one name="customer" class="com.theitroad.hibernate.model.Customer" cascade="save-update" </class> </hibernate-mapping>
上面要注意的重要点是客户属性的Hibernate "一对一"元素。
customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "https://hibernate.org/dtd/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="com.theitroad.hibernate.model.Customer" table="CUSTOMER"> <id name="id" type="long"> <column name="txn_id" <generator class="foreign"> <param name="property">txn</param> </generator> </id> <one-to-one name="txn" class="com.theitroad.hibernate.model.Txn" constrained="true"></one-to-one> <property name="name" type="string"> <column name="cust_name"></column> </property> <property name="email" type="string"> <column name="cust_email"></column> </property> <property name="address" type="string"> <column name="cust_address"></column> </property> </class> </hibernate-mapping>
generator class =" foreign"是用于Hibernate 外键实现的重要部分。
Hibernate 配置文件
这是基于XML的Hibernate 映射配置的Hibernate 配置文件。
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "https://hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.password">hyman123</property> <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property> <property name="hibernate.connection.username">hyman</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.show_sql">true</property> <mapping resource="txn.hbm.xml" <mapping resource="customer.hbm.xml" </session-factory> </hibernate-configuration>
Hibernate配置文件很简单,它具有数据库连接属性和hibernate映射资源。
Hibernate SessionFactory实用程序
这是用于创建Hibernate SessionFactory实例的实用程序类。
package com.theitroad.hibernate.util; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class HibernateUtil { private static SessionFactory sessionFactory; private static SessionFactory buildSessionFactory() { try { //Create the SessionFactory from hibernate.cfg.xml Configuration configuration = new Configuration(); configuration.configure("hibernate.cfg.xml"); System.out.println("Hibernate Configuration loaded"); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); System.out.println("Hibernate serviceRegistry created"); SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry); return sessionFactory; } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); ex.printStackTrace(); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { if(sessionFactory == null) sessionFactory = buildSessionFactory(); return sessionFactory; } }
就是这样,让我们编写一个测试程序来测试Hibernate 的一对一基于xml的映射配置。
Hibernate 一对一映射XML配置测试程序
在Hibernate 的一对一映射示例测试程序中,首先我们将创建Txn对象并将其保存。
将其保存到数据库后,我们将使用生成的ID来检索Txn对象并进行打印。
package com.theitroad.hibernate.main; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Customer; import com.theitroad.hibernate.model.Txn; import com.theitroad.hibernate.util.HibernateUtil; public class HibernateOneToOneMain { public static void main(String[] args) { Txn txn = buildDemoTransaction(); SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try{ //Get Session sessionFactory = HibernateUtil.getSessionFactory(); session = sessionFactory.getCurrentSession(); System.out.println("Session created"); //start transaction tx = session.beginTransaction(); //Save the Model object session.save(txn); //Commit transaction tx.commit(); System.out.println("Transaction ID="+txn.getId()); //Get Saved Trasaction Data printTransactionData(txn.getId(), sessionFactory); }catch(Exception e){ System.out.println("Exception occured. "+e.getMessage()); e.printStackTrace(); }finally{ if(!sessionFactory.isClosed()){ System.out.println("Closing SessionFactory"); sessionFactory.close(); } } } private static void printTransactionData(long id, SessionFactory sessionFactory) { Session session = null; Transaction tx = null; try{ //Get Session sessionFactory = HibernateUtil.getSessionFactory(); session = sessionFactory.getCurrentSession(); //start transaction tx = session.beginTransaction(); //Save the Model object Txn txn = (Txn) session.get(Txn.class, id); //Commit transaction tx.commit(); System.out.println("Transaction Details=\n"+txn); }catch(Exception e){ System.out.println("Exception occured. "+e.getMessage()); e.printStackTrace(); } } private static Txn buildDemoTransaction() { Txn txn = new Txn(); txn.setDate(new Date()); txn.setTotal(100); Customer cust = new Customer(); cust.setAddress("Bangalore, San Franceco"); cust.setEmail("[email protected]"); cust.setName("hyman Kumar"); txn.setCustomer(cust); cust.setTxn(txn); return txn; } }
现在,当我们在Hibernate 测试程序中运行一对一映射时,将得到以下输出。
Hibernate Configuration loaded Hibernate serviceRegistry created Session created Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?) Hibernate: insert into CUSTOMER (cust_name, cust_email, cust_address, txn_id) values (?, ?, ?, ?) Transaction ID=19 Hibernate: 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_, customer1_.txn_id as txn_id1_0_1_, customer1_.cust_name as cust_nam2_0_1_, customer1_.cust_email as cust_ema3_0_1_, customer1_.cust_address as cust_add4_0_1_ from TRANSACTION txn0_ left outer join CUSTOMER customer1_ on txn0_.txn_id=customer1_.txn_id where txn0_.txn_id=? Transaction Details= 19, 100.0, hyman Kumar, [email protected], Bangalore, San Franceco Closing SessionFactory
如您所见,它工作正常,我们能够使用交易ID从两个表中检索数据。
在内部检查Hibernate使用的SQL来获取数据,使用Hibernate的联接从两个表中获取数据。
Hibernate 一对一映射注释
在上一节中,我们了解了如何将基于XML的配置用于Hibernate 一对一映射,现在让我们看看如何使用JPA和Hibernate批注实现相同的目的。
Hibernate 配置文件
hibernate-annotation.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "https://hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.password">hyman123</property> <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property> <property name="hibernate.connection.username">hyman</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.show_sql">true</property> <mapping class="com.theitroad.hibernate.model.Txn1" <mapping class="com.theitroad.hibernate.model.Customer1" </session-factory> </hibernate-configuration>
Hibernate 配置很简单,您可以看到我有两个模型类将与注释一起使用-Txn1和Customer1。
Hibernate 一对一映射注释示例模型类
对于Hibernate 的一对一映射注释配置,模型类是最重要的部分。
让我们看看我们的模型类的外观。
package com.theitroad.hibernate.model; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.Cascade; @Entity @Table(name="TRANSACTION") public class Txn1 { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="txn_id") private long id; @Column(name="txn_date") private Date date; @Column(name="txn_total") private double total; @OneToOne(mappedBy="txn") @Cascade(value=org.hibernate.annotations.CascadeType.SAVE_UPDATE) private Customer1 customer; @Override public String toString(){ return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress(); } //Getter-Setter methods, omitted for clarity }
请注意,大多数注释来自Java Persistence API,因为Hibernate提供了它的实现。
但是,对于级联,我们将需要使用Hibernate注释org.hibernate.annotations.Cascade和枚举org.hibernate.annotations.CascadeType。
package com.theitroad.hibernate.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; @Entity @Table(name="CUSTOMER") public class Customer1 { @Id @Column(name="txn_id", unique=true, nullable=false) @GeneratedValue(generator="gen") @GenericGenerator(name="gen", strategy="foreign", parameters={@Parameter(name="property", value="txn")}) private long id; @Column(name="cust_name") private String name; @Column(name="cust_email") private String email; @Column(name="cust_address") private String address; @OneToOne @PrimaryKeyJoinColumn private Txn1 txn; //Getter-Setter methods }
注意,我们需要使用@GenericGenerator,以便从txn使用id而不是生成它。
Hibernate SessionFactory Utility类
创建SessionFactory独立于我们提供Hibernate 映射的方式。
我们用于创建SessionFactory的实用程序类如下所示。
package com.theitroad.hibernate.util; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class HibernateAnnotationUtil { private static SessionFactory sessionFactory; private static SessionFactory buildSessionFactory() { try { //Create the SessionFactory from hibernate-annotation.cfg.xml Configuration configuration = new Configuration(); configuration.configure("hibernate-annotation.cfg.xml"); System.out.println("Hibernate Annotation Configuration loaded"); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); System.out.println("Hibernate Annotation serviceRegistry created"); SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry); return sessionFactory; } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); ex.printStackTrace(); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { if(sessionFactory == null) sessionFactory = buildSessionFactory(); return sessionFactory; } }
Hibernate 一对一映射注释示例测试程序
这是Hibernate 的一对一映射注释示例的简单测试程序。
package com.theitroad.hibernate.main; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Customer1; import com.theitroad.hibernate.model.Txn1; import com.theitroad.hibernate.util.HibernateAnnotationUtil; public class HibernateOneToOneAnnotationMain { public static void main(String[] args) { Txn1 txn = buildDemoTransaction(); SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try{ //Get Session sessionFactory = HibernateAnnotationUtil.getSessionFactory(); session = sessionFactory.getCurrentSession(); System.out.println("Session created using annotations configuration"); //start transaction tx = session.beginTransaction(); //Save the Model object session.save(txn); //Commit transaction tx.commit(); System.out.println("Annotation Example. Transaction ID="+txn.getId()); //Get Saved Trasaction Data printTransactionData(txn.getId(), sessionFactory); }catch(Exception e){ System.out.println("Exception occured. "+e.getMessage()); e.printStackTrace(); }finally{ if(sessionFactory != null && !sessionFactory.isClosed()){ System.out.println("Closing SessionFactory"); sessionFactory.close(); } } } private static void printTransactionData(long id, SessionFactory sessionFactory) { Session session = null; Transaction tx = null; try{ //Get Session sessionFactory = HibernateAnnotationUtil.getSessionFactory(); session = sessionFactory.getCurrentSession(); //start transaction tx = session.beginTransaction(); //Save the Model object Txn1 txn = (Txn1) session.get(Txn1.class, id); //Commit transaction tx.commit(); System.out.println("Annotation Example. Transaction Details=\n"+txn); }catch(Exception e){ System.out.println("Exception occured. "+e.getMessage()); e.printStackTrace(); } } private static Txn1 buildDemoTransaction() { Txn1 txn = new Txn1(); txn.setDate(new Date()); txn.setTotal(100); Customer1 cust = new Customer1(); cust.setAddress("San Jose, USA"); cust.setEmail("[email protected]"); cust.setName("hyman Kr"); txn.setCustomer(cust); cust.setTxn(txn); return txn; } }
这是我们执行上述程序时的输出片段。
Hibernate Annotation Configuration loaded Hibernate Annotation serviceRegistry created Session created using annotations configuration Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?) Hibernate: insert into CUSTOMER (cust_address, cust_email, cust_name, txn_id) values (?, ?, ?, ?) Annotation Example. Transaction ID=20 Hibernate: 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_, customer1x1_.txn_id as txn_id1_0_1_, customer1x1_.cust_address as cust_add2_0_1_, customer1x1_.cust_email as cust_ema3_0_1_, customer1x1_.cust_name as cust_nam4_0_1_ from TRANSACTION txn1x0_ left outer join CUSTOMER customer1x1_ on txn1x0_.txn_id=customer1x1_.txn_id where txn1x0_.txn_id=? Annotation Example. Transaction Details= 20, 100.0, hyman Kr, [email protected], San Jose, USA Closing SessionFactory
请注意,输出类似于Hibernate 一对一基于XML的配置。