JPA -一对多双向联系关系与级联操作
Order.java
- package cn.itcast.bean;
- import java.util.HashSet;
- import java.util.Set;
- import javax.persistence.CascadeType;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.Id;
- import javax.persistence.OneToMany;
- @Entity
- public class Order {
- private String orderId;
- private Float amount = 0f;
- private Set<OrderItem> items = new HashSet<OrderItem>();
- @Id //要注意:目前JPA规范并没有提供UUID这种生成策略,目前主键值只提供了整型的生成方式,所以@GeneratedValue这个注解就不能在这里用上,不能对字符串进行id自增长。
- @Column(length = 12)
- public String getOrderId() {
- return orderId;
- }
- public void setOrderId(String orderId) {
- this.orderId = orderId;
- }
- @Column(nullable = false)
- public Float getAmount() {
- return amount;
- }
- public void setAmount(Float amount) {
- this.amount = amount;
- }
- @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST,
- CascadeType.MERGE, CascadeType.REMOVE }) //设置成一对多的关系。
- public Set<OrderItem> getItems() {
- return items;
- }
- public void setItems(Set<OrderItem> items) {
- this.items = items;
- }
- }
OrderItem.java
- package cn.itcast.bean;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.Id;
- @Entity
- public class OrderItem {
- private Integer id;
- private String productName;
- private Float sellPrice = 0f; //默认值为0。
- private Order order;
- @Id
- @GeneratedValue //id自增长方式生成主键。
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- @Column(length = 40, nullable = false)
- public String getProductName() {
- return productName;
- }
- public void setProductName(String productName) {
- this.productName = productName;
- }
- @Column(nullable = false)
- public Float getSellPrice() {
- return sellPrice;
- }
- public void setSellPrice(Float sellPrice) {
- this.sellPrice = sellPrice;
- }
- public Order getOrder() {
- return order;
- }
- public void setOrder(Order order) {
- this.order = order;
- }
- }
在JPA里面,一对多关系(1-n):
多的一方为关系维护端,关系维护端负责外键记录的更新(如果是条字段就负责字段的更新,如果是多对多关系中的中间表就负责中间表记录的更新),关系被维护端是没有权力更新外键记录(外键字段)的。
CascadeType的选项有,看图:
CascadeType.REFRESH:级联刷新,也就是说,当你刚开始获取到了这条记录,那么在你处理业务过程中,这条记录被另一个业务程序修改了(数据库这条记录被修改了),那么你获取的这条数据就不是最新的数据,那你就要调用实体管理器里面的refresh方法来刷新实体,所谓刷新,大家一定要记住方向,它是获取数据,相当于执行select语句的(但不能用select,select方法返回的是EntityManager缓存中的数据,不是数据库里面最新的数据),也就是重新获取数据。
CascadeType.PERSIST:级联持久化,也就是级联保存。保存order的时候也保存orderItem,如果在数据库里已经存在与需要保存的orderItem相同的id记录,则级联保存出错。
CascadeType.MERGE: 级联更新,也可以叫级联合并;当对象Order处于游离状态时,对对象Order里面的属性作修改,也修改了Order里面的orderItems,当要更新对象Order时,是否也要把对orderItems的修改同步到数据库呢?这就是由CascadeType.MERGE来决定的,如果设了这个值,那么Order处于游离状态时,会先update order,然后for循环update orderItem,如果没设CascadeType.MERGE这个值,就不会出现for循环update orderItem语句。
所以说,级联更新是控制对Order的更新是否会波及到orderItems对象。也就是说对Order进行update操作的时候,orderItems是否也要做update操作呢?完全是由CascadeType.MERGE控制的。
CascadeType.REMOVE:当对Order进行删除操作的时候,是否也要对orderItems对象进行级联删除操作呢?是的则写,不是的则不写。
如果在应用中,要同时使用这四项的话,可以改成cascade = CascadeType.ALL
应用场合问题:这四种级联操作,并不是对所有的操作都起作用,只有当我们调用实体管理器的persist方法的时候,CascadeType.PERSIST才会起作用;同样道理,只有当我们调用实体管理器的merge方法的时候,CascadeType.MERGE才会起作用,其他方法不起作用。 同样道理,只有当我们调用实体管理器的remove方法的时候,CascadeType.REMOVE才会起作用。
注意: Query query = em.createQuery("delete from Person o where o.id=?1");这种删除会不会起作用呢?是不会起作用的,因为配置里那四项都是针对实体管理器的对应的方法。