Hibernate ORM 之 双向一对多
多方:多方持有一方的引用
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinColumn(name = “cid”, foreignKey = @ForeignKey(name = “fk_c_o”))
一方:一方持有多方的集合
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, mappedBy = “customer”)
其中mappedBy指定由多方维护关联关系,保存实体时将不会产生update语句。如果不指定mappedBy属性,则需要使用@JoinColumn(name = “cid”),否则hibernate将会生成中间表来维护实体之间的关联关系。
注意:在hibernate5中,标记为mappedBy的关联不能定义像@JoinTable或@JoinColumn这样的数据库映射,通俗来说mappedBy和@JoinColumn、@JoinTable不能同时使用。(貌似hibernate3.3.2之前可以同使用)
1 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.libill</groupId>
<artifactId>hibernate-demo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>hibernate-demo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<finalName>hibernate-demo</finalName>
</build>
</project>
2 hibernate.cfg.xml配置文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://192.168.145.128:3306/hibernate?useUnicode=true&characterEncoding=utf-8</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="connection.autocommit">false</property>
<!-- DB schema will be updated if needed -->
<property name="hbm2ddl.auto">create</property>
<!-- 显示sql语句 -->
<property name="show_sql">true</property>
<!-- 显示sql语句前进行格式化 -->
<property name="format_sql">true</property>
<!-- 方言: MySQL55Dialect将会使用InnoDB引擎 -->
<property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>
<!-- 双向一对多 -->
<mapping class="com.libill.one2manysx.Customer"/>
<mapping class="com.libill.one2manysx.Order"/>
</session-factory>
</hibernate-configuration>
3 测试方法
package com.libill.one2manysx;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.EnumSet;
@SuppressWarnings(value = {"unused"})
public class One2ManySXTest {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
private SchemaExport schemaExport;
@Before
public void init() {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void destroy() {
transaction.commit();
session.close();
sessionFactory.close();
}
/**
* 测试实体对象的保存
*/
@Test
public void saveTest() {
Customer customer = new Customer("张三", "13982502467");
Order order = new Order("馒头");
order.setCustomer(customer);
customer.getOrders().add(order);
session.save(customer);
}
/**
* 测试根据实体对象生成数据库表,只创建表结构
*/
@Test
public void testSchema() {
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
Metadata metadata = new MetadataSources(serviceRegistry).buildMetadata();
SchemaExport schemaExport = new SchemaExport();
schemaExport.create(EnumSet.of(TargetType.DATABASE), metadata);
}
}
实体类(使用@JoinColumn,不使用mappedBy属性)
package com.libill.one2manysx;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_customer")
@SuppressWarnings(value = {"all"})
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String phone;
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@JoinColumn(name = "cid")
private Set<Order> orders = new HashSet<Order>();
public Customer() {
}
public Customer(String name, String phone) {
this.name = name;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
package com.libill.one2manysx;
import javax.persistence.*;
@Entity
@Table(name = "t_order")
@SuppressWarnings(value = {"all"})
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String content;
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinColumn(name = "cid", foreignKey = @ForeignKey(name = "fk_c_o"))
// foreignKey自定义外键名称,如果不写,则hibernate默认创建一个名称,多方或一方有一个指定即可,两方都写也可以。
private Customer customer;
public Order() {
}
public Order(String content) {
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
使用@JoinColumn的结果
Hibernate:
insert
into
t_customer
(name, phone)
values
(?, ?)
Hibernate:
insert
into
t_order
(content, cid)
values
(?, ?)
Hibernate:
update
t_order
set
cid=?
where
id=?
可以看到,除了两条插入语句,还有一条update语句。
实体类(使用mappedBy,不使用@JoinColumn)
package com.libill.one2manysx;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_customer")
@SuppressWarnings(value = {"all"})
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String phone;
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, mappedBy = "customer")
private Set<Order> orders = new HashSet<Order>();
public Customer() {
}
public Customer(String name, String phone) {
this.name = name;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
package com.libill.one2manysx;
import javax.persistence.*;
@Entity
@Table(name = "t_order")
@SuppressWarnings(value = {"all"})
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String content;
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinColumn(name = "cid", foreignKey = @ForeignKey(name = "fk_c_o"))
private Customer customer;
public Order() {
}
public Order(String content) {
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
使用mappedBy属性结果
Hibernate:
insert
into
t_customer
(name, phone)
values
(?, ?)
Hibernate:
insert
into
t_order
(content, cid)
values
(?, ?)
从结果可以看出,只执行了两条插入语句,没有更新语句。