- 浏览: 11411 次
- 性别:
- 来自: 上海
文章分类
最新评论
Hibernate关联映射是Hibernate中比较难用好知识点, 一方面两个实体之间的关系类型比较多, 有单向映射、双向映射; 还有ManyToOne, OneToOne, OneToMany, ManyToMany, 这样算下来会有2*4=8种, 通过不同逻辑映射产生的物理表也比较多, 当然其中一部分是类似的; 复杂的另一方面体现在对关联实体的操作可能对被关联实体产生的影响上面, 包括级联属性(CASCADE)、抓取属性(FETCH)等, 如果配置不好会适得其反. 因此在这里我们通过逐个实现每一种关联大致了解关联映射的概念和基本使用.
实体类: Person和Address, 在不同场景下两个实体的关系不同.
Hibernate实现:Hibernate4 + JPA, 基于注解实现.
Hibernate实现:Hibernate4 + JPA, 基于注解实现.
包的组织形式如下图所示, 其中Tester是测试类, hibernate.cfg.xml是配置文件.
hibernate配置文件如下, 后续的用于测试不同关联映射的包使用相同的配置, 只是映射的实体类不同而已.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">com.ibm.db2.jcc.DB2Driver</property> <property name="connection.url">jdbc:db2://127.0.0.1:60003/HIBER</property> <property name="connection.username">*****</property> <property name="connection.password">******</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">3</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.DB2Dialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">update</property> <!-- <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml" /> --> <mapping class="azure.hibernate4.associations.unidi.many2one.Person" /> <mapping class="azure.hibernate4.associations.unidi.many2one.Address" /> </session-factory> </hibernate-configuration>
在Hibernate4中创建SessionFactory的方式与Hibernate3有一些不一样, 但这里不是讨论的重点, 一下几个包中的Tester.java使用相同的取得SessionFactory方式, 代码如下:
public SessionFactory sessionFactory; public Session getCurrentSession() { String filePath = this.getClass().getPackage().getName() .replaceAll("\\.", "/"); if (sessionFactory == null) { Configuration cfg = new Configuration().configure(Thread .currentThread().getContextClassLoader() .getResource(filePath + "/hibernate.cfg.xml")); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() .applySettings(cfg.getProperties()).buildServiceRegistry(); sessionFactory = cfg.buildSessionFactory(serviceRegistry); } return sessionFactory.getCurrentSession(); }
下面我们一一测试每一种关联映射。
1. 单向关联
1.1 单向ManyToOne关联
//Person.java package azure.hibernate4.associations.unidimany2one; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "PERSON") public class Person implements Serializable { private static final long serialVersionUID = -1097173835933422124L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "ADDRESS_ID") private Address address; public int getPersonId() { return personId; } public void setPersonId(int personId) { this.personId = personId; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
//Address.java package azure.hibernate4.associations.unidimany2one; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "ADDRESS") public class Address implements Serializable { private static final long serialVersionUID = 3794514024483047170L; @Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name; public int getAddressId() { return addressId; } public void setAddressId(int addressId) { this.addressId = addressId; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
由Hibernate生成的表物理视图如下, 在ManyToOne关系中是在主表中生成一个外键.
1.2 单向OneToOne关联
映射部分代码Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "ADDRESS_ID") private Address address;
Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name;
生成的建表SQL语句如下:
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) Hibernate: create table PERSON (personId integer generated by default as identity, ADDRESS_ID integer, primary key (personId)) Hibernate: alter table PERSON add constraint FK8C768F5591A4FE5E foreign key (ADDRESS_ID) references ADDRESS
生成的表的物理视图如下:
1.3 单向OneToMany
关联部分代码Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<Address> address;
Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name;
生成的建表SQL语句如下:
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) Hibernate: create table PERSON (personId integer generated by default as identity, primary key (personId)) Hibernate: create table PERSON_ADDRESS (PERSON_personId integer not null, address_ADDRESS_ID integer not null, primary key (PERSON_personId, address_ADDRESS_ID)) Hibernate: alter table PERSON_ADDRESS add constraint UK_9E2338EA65485A71 unique (address_ADDRESS_ID) Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EAD006FE6A foreign key (address_ADDRESS_ID) references ADDRESS Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EA495AB8A foreign key (PERSON_personId) references PERSON
物理表视图如下, 看到Hibernate使用连接表来实现单向OneToMany, 根据Hibernate文档的说明:
写道
A unidirectional one-to-many association on a foreign key is an unusual case, and is not recommended.
1.4 单向ManyToMany
Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<Address> address;Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name;
建表SQL
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) Hibernate: create table PERSON (personId integer generated by default as identity, primary key (personId)) Hibernate: create table PERSON_ADDRESS (PERSON_personId integer not null, address_ADDRESS_ID integer not null, primary key (PERSON_personId, address_ADDRESS_ID)) Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EADD54AFC1 foreign key (address_ADDRESS_ID) references ADDRESS Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EABAB0F353 foreign key (PERSON_personId) references PERSON物理表
2. 双向关联
2.1 双向ManyToMany
Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<Address> address;Address.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<Address> address;建表SQL
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) Hibernate: create table ADDRESS_PERSON (ADDRESS_ADDRESS_ID integer not null, person_personId integer not null, primary key (ADDRESS_ADDRESS_ID, person_personId)) Hibernate: create table PERSON (personId integer generated by default as identity, primary key (personId)) Hibernate: create table PERSON_ADDRESS (PERSON_personId integer not null, address_ADDRESS_ID integer not null, primary key (PERSON_personId, address_ADDRESS_ID)) Hibernate: alter table ADDRESS_PERSON add constraint FK3672AE20593E71E foreign key (person_personId) references PERSON Hibernate: alter table ADDRESS_PERSON add constraint FK3672AE20EED03556 foreign key (ADDRESS_ADDRESS_ID) references ADDRESS Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EAEED03556 foreign key (address_ADDRESS_ID) references ADDRESS Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EA593E71E foreign key (PERSON_personId) references PERSON物理表视图如下
很遗憾, 这并不是我们所期望的的表结构. 对于双向ManyToMany, 使用一个中间表就够了, 因此我们需要对实体类的配置作如下修改
Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "PERSON_ADDRESS", joinColumns = { @JoinColumn(name = "ADDRESS_ID") }, inverseJoinColumns = { @JoinColumn(name = "PERSON_ID") }) private Set<Address> address;Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinTable(name = "PERSON_ADDRESS", joinColumns = { @JoinColumn(name = "PERSON_ID") }, inverseJoinColumns = { @JoinColumn(name = "ADDRESS_ID") }) private Set<Person> person;这时的建表SQL语句如下:
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) Hibernate: create table PERSON (personId integer generated by default as identity, primary key (personId)) Hibernate: create table PERSON_ADDRESS (PERSON_ID integer not null, ADDRESS_ID integer not null, primary key (ADDRESS_ID, PERSON_ID)) Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EA97561B8A foreign key (ADDRESS_ID) references PERSON Hibernate: alter table PERSON_ADDRESS add constraint FK9E2338EABC62752A foreign key (PERSON_ID) references ADDRESS
物理表如下:
2.2 双向ManyToOne关联
双向ManyToOne关联, 在1的一端需要有到N的一段的集合字段, 在N的一端需要到1的一端的字段. 在双向一对多关联中建议不用连接表, 而直接在多的一端加外键.
Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "ADDRESS_ID") private Address address;
Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name; @OneToMany(mappedBy = "address", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<Person> persons;
建表SQL如下:
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), primary key (ADDRESS_ID)) 2013-5-22 16:42:45 org.hibernate.tool.hbm2ddl.SchemaExport perform Hibernate: create table PERSON (personId integer generated by default as identity, ADDRESS_ID integer, primary key (personId)) Hibernate: alter table PERSON add constraint FK8C768F5592A339F2 foreign key (ADDRESS_ID) references ADDRESS
物理表结构:
2.3 双向OneToOne关联
通过双向OneToOne关联可以从任意一端导航到另一端, 在两个实体类里面需要同时定义到另一端的属性. 物理表结构方面, 在任意一端建立一个外键.
Person.java
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int personId; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Address address;
Address.java
@Id @Column(name = "ADDRESS_ID") private int addressId; @Column(name = "ADDRESS_NAME") private String name; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) private Person person;
建表语句如下:
Hibernate: create table ADDRESS (ADDRESS_ID integer not null, ADDRESS_NAME varchar(255), person_personId integer, primary key (ADDRESS_ID)) Hibernate: create table PERSON (personId integer generated by default as identity, address_ADDRESS_ID integer, primary key (personId)) Hibernate: alter table ADDRESS add constraint FKE66327D4A65E7D16 foreign key (person_personId) references PERSON Hibernate: alter table PERSON add constraint FK8C768F5567585E5E foreign key (address_ADDRESS_ID) references ADDRESS
物理表结构如下:
可以看到Hibernate同时在两张表上都添加了外键.
相关推荐
5. **更新数据库表**:在生成映射文件后,还可以结合Hibernate的SchemaExport工具生成或更新数据库表结构。 这样的自动化过程可以帮助开发者节省大量时间,并且减少人为错误。在实际开发中,例如使用Eclipse或...
在Java的持久化框架Hibernate中,关系映射是数据库对象之间的关联方式,它允许我们将复杂的数据库结构映射到Java对象上。"Hibernate one-to-many / many-to-one关系映射"是两个基本的关系类型,用于表示实体间的关联...
`生成hibernate映射文件工具`是为了简化这一过程而设计的,它自动根据数据库的表结构生成对应的Hibernate映射文件,极大地提高了开发效率。 首先,我们需要理解Hibernate的核心概念。Hibernate是一个优秀的Java ORM...
### Hibernate基础之关联映射与级联操作 #### 第一部分:主键生成策略与对象状态管理 ##### 主键生成策略 在使用Hibernate框架时,合理的主键生成策略能够极大地简化开发工作并提升应用性能。Hibernate提供了多种...
在Hibernate自动生成表结构时,可能会遇到主键错乱的问题,这通常是由于配置不当或实体关系处理不正确导致的。要解决这个问题,可以: - 确保每个实体的主键都有`@Id`注解,并且有合适的生成策略,如`@...
4. 使用工具或API生成数据库:有了映射文件,你可以使用Hibernate的`SchemaExport`工具或者编程方式执行`sessionFactory.createSchema()`方法来根据映射文件生成数据库表。这将在数据库中创建对应的表结构。 三、...
Middlegen是一款基于Ant的任务,能够从数据库模式生成Hibernate的元数据XML文件,这些文件包含了关于表结构、字段和关系的信息,用于驱动Hibernate自动创建Java对象和数据库表之间的映射。通过Middlegen,开发者可以...
本文将深入探讨如何利用Hibernate的特性来实现动态生成表结构,以及如何处理表与表之间的关系。 一、Hibernate概述 Hibernate是一个开源的Java库,它的主要功能是将Java类与数据库表进行映射,使得程序员可以使用...
设置为`update`则会在已有表基础上更新结构,而`validate`则只会验证表结构是否与实体类匹配。 4. **SessionFactory和Session**: - `SessionFactory`是Hibernate的核心,它是线程安全的,一个应用只需要一个...
- .hbm.xml文件是Hibernate理解Java对象与数据库表之间关系的桥梁,包含了实体类与数据库表的映射信息,如字段映射、关联关系、继承结构等。 - 自动生成的好处是减少了手动编写映射文件的工作量,降低了出错的可能...
首先,我们需要了解Hibernate映射文件的基本结构。通常,一个映射文件以`.hbm.xml`为扩展名,它使用XML格式来描述Java类和数据库表的对应关系。映射文件包含了类名、表名、字段及其数据类型等信息。例如: ```xml ...
生成的映射文件`address.hbm.xml`包含了表`ADDRESS`的字段映射信息,而对应的Java实体类`Address.java`则包含了表结构对应的属性和getter/setter方法。这两个文件一起构成了Hibernate与数据库交互的基础。 通过...
3. 关联映射:通过@ManyToOne、@OneToMany等注解定义实体之间的关联关系,实现对象的懒加载或立即加载。 4. 事务管理:使用Hibernate的Transaction API进行事务控制,保证数据的一致性和完整性。 5. 性能调优:根据...
3. **逆向工程**:执行DDL2Java工具,该工具会根据数据库中的表结构生成对应的Java实体类和.hbm.xml映射文件。你可以选择生成全部表的映射,或者指定特定的表进行生成。 4. **解析生成的文件**:生成的Java类通常...
#### Hibernate映射文件结构 1. **DTD声明**:映射文件的头部会包含DTD声明,确保文件遵循正确的DTD规范。例如: ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//...
2. **中间表的自动创建**:Hibernate默认会根据`@ManyToMany`和`@JoinTable`的配置自动生成中间表,但也可以手动指定表结构。 3. **关联的管理**:在业务逻辑中,我们需要添加或删除关联。例如,当一个学生选修一门...
"Hibernate自动生成持久化类和映射文件"这个话题主要涉及如何利用myEclipse这款集成开发环境的反向工程功能,快速地根据数据库中的表结构生成对应的Hibernate配置文件、映射文件以及持久化类。下面将详细介绍这一...
4. 运行代码生成工具,它会基于数据库表结构创建实体类、配置文件和映射文件。 5. 在生成的文件中进行必要的调整,例如添加业务逻辑、验证规则等。 通过这个过程,开发者可以快速地建立一个与数据库交互的基础框架...
在3.4.0.GA版本中,它使得开发者无需依赖XML配置文件,就能通过在实体类上添加特定注解来描述数据库表结构和字段属性。这提高了代码的可读性和开发效率,减少了配置文件的维护成本。 1. **注解基础** - `@Entity`:...
在Java的持久化框架Hibernate中,一对一(One-to-One)关联映射是常见的关系数据库模型。本篇文章将深入探讨两种实现一对一关联的方式:主键关联(Primary Key Join)和唯一外键关联(ForeignKey Join),并结合源码...