本文讨论:在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,达到优化的效果。