本文讨论:在Hibernate双向一对多级联保存中,SQL条数过多的问题
1、建立表结构
use `hibernate-orm`;
drop table if exists `orders`;
drop table if exists `Customer`;
/* 客户表(单方) */
create table `Customer`
(
id int primary key auto_increment,
name varchar(50) comment '客户姓名',
age int comment '客户年龄'
);
/* 订单表(多方) */
create table `orders`
(
id int primary key auto_increment,
name varchar(50) comment '订单名称',
orderno int comment '订单号',
customer_id int comment '所属的客户',
constraint foreign key(`customer_id`) references `Customer`(`id`)
);
select * from `orders`;
select * from `customer`;
2、建立Customer实体对象
package dai.hao.hibernate.one2many.ano._double;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* 客户类,单方
*
* @author Horace <br/>
*
* 2014年8月27日 下午9:08:36
*/
@Entity
@Table(name = "Customer")
public class Customer
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
// 设置关联关系
@OneToMany(targetEntity = Order.class, cascade = CascadeType.ALL)
// name指定对方表的外键字段
@JoinColumn(name = "customer_id")
private Set<Order> orders;
public Set<Order> getOrders()
{
return orders;
}
public void setOrders(Set<Order> orders)
{
this.orders = orders;
}
public Customer()
{
}
public Customer(String name, int age)
{
super();
this.name = name;
this.age = age;
}
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 int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public String toString()
{
return "Customer [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
3、建立Order实体对象
package dai.hao.hibernate.one2many.ano._double;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* 订单类,多方
*
* @author Horace <br/>
*
* 2014年8月27日 下午9:09:41
*/
@Entity
@Table(name = "orders")
public class Order
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int orderno;
@ManyToOne(targetEntity = Customer.class, cascade = CascadeType.ALL)
@JoinColumn(name = "customer_id")
private Customer customer;
public Customer getCustomer()
{
return customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
public Order()
{
}
public Order(String name, int orderno)
{
super();
this.name = name;
this.orderno = orderno;
}
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 int getOrderno()
{
return orderno;
}
public void setOrderno(int orderno)
{
this.orderno = orderno;
}
@Override
public String toString()
{
return "Order [id=" + id + ", name=" + name + ", orderno=" + orderno + "]";
}
}
4、不需要额外的映射关系的配置文件
5、执行测试
package dai.hao.hibernate.one2many.ano._double;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
public class Main
{
@Test
public void testCascadeAdd()
{
// 保存客户级联保存订单
Session session = HiberUtils.getCurrentSession();
Transaction transaction = session.getTransaction();
transaction.begin();
Customer customer = new Customer("Horace", 22);
Order order1 = new Order("订单1", 123456);
Order order2 = new Order("订单2", 234567);
Set<Order> orders = new HashSet<Order>();
orders.add(order1);
orders.add(order2);
customer.setOrders(orders);
session.save(customer);
transaction.commit();
HiberUtils.close();
}
}
6、执行结果(双方都维护关联关系的情况下,可以发现多了两条SQL)
Hibernate: insert into Customer (age, name) values (?, ?)
Hibernate: insert into orders (customer_id, name, orderno) values (?, ?, ?)
Hibernate: insert into orders (customer_id, name, orderno) values (?, ?, ?)
Hibernate: update orders set customer_id=? where id=?
Hibernate: update orders set customer_id=? where id=?
7、修改Customer实体对象,让多方(Order)维护关联关系
package dai.hao.hibernate.one2many.ano._double;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* 客户类,单方
*
* @author Horace <br/>
*
* 2014年8月27日 下午9:08:36
*/
@Entity
@Table(name = "Customer")
public class Customer
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
// 设置关联关系
/*
* 在双向关联关系中,mappedBy属性表示由对方维护关联关系,其属性值是对方实体中本方的类属姓名
* 如:private Customer customer;
* 相当于xml配置中的inverse="true"。
* 此时需要注意的是不要写@JoinColumn,因为在本方已经不需要维护关联关系了
*/
@OneToMany(mappedBy="customer", cascade = CascadeType.ALL)
private Set<Order> orders;
public Set<Order> getOrders()
{
return orders;
}
public void setOrders(Set<Order> orders)
{
this.orders = orders;
}
public Customer()
{
}
public Customer(String name, int age)
{
super();
this.name = name;
this.age = age;
}
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 int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public String toString()
{
return "Customer [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
8、测试–注意:测试用例有修改
package dai.hao.hibernate.one2many.ano._double;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
public class Main
{
@Test
public void testCascadeAdd()
{
// 保存客户级联保存订单
Session session = HiberUtils.getCurrentSession();
Transaction transaction = session.getTransaction();
transaction.begin();
/**
* 特别注意: 因为mappedBy是定义在customer中,即Customer类不负责维护级联关系.即维护者是Order.所以,
* 要将Customer的数据,赋给Order,即用Order的setCustomer()方法去捆定Customer数据;
*/
Customer customer = new Customer("Horace", 22);
Order order1 = new Order("订单1", 123456);
Order order2 = new Order("订单2", 234567);
Set<Order> orders = new HashSet<Order>();
orders.add(order1);
orders.add(order2);
customer.setOrders(orders);
order1.setCustomer(customer);
order2.setCustomer(customer);
session.save(customer);
transaction.commit();
HiberUtils.close();
}
}
9、执行结果
Hibernate: insert into Customer (age, name) values (?, ?)
Hibernate: insert into orders (customer_id, name, orderno) values (?, ?, ?)
Hibernate: insert into orders (customer_id, name, orderno) values (?, ?, ?)
总结:在双向关联关系中,需要设置xml–>inverse=”true”,注解:mappedBy=”对方实体中本方属性名”,把关联关系交给多方表控制,那么会省去不必要的SQL,达到优化的效果。