JPA

来源:互联网 发布:证件拍照软件下载 编辑:程序博客网 时间:2024/06/06 14:10

双向多对一关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。

可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。

在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称


【1】修改Order和Customer

Order:Customer = N:1。

Order如下:

@Table(name="JPA_ORDERS")@Entitypublic class Order {    private Integer id;    private String orderName;    private Customer customer;    @GeneratedValue    @Id    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    @Column(name="ORDER_NAME")    public String getOrderName() {        return orderName;    }    public void setOrderName(String orderName) {        this.orderName = orderName;    }    //映射单向 n-1的关联关系    //使用@ManyToOne来映射多对一的关联关系    //使用@JoinColumn 来映射外键               //可使用 @ManyToOne 的fetch 属性来修改默认的关联属性的加载策略    @JoinColumn(name="CUSTOMER_ID")//  @ManyToOne(fetch=FetchType.LAZY)    @ManyToOne(fetch=FetchType.EAGER)    public Customer getCustomer() {        return customer;    }    public void setCustomer(Customer customer) {        this.customer = customer;    }}

Customer如下:

@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")@Cacheable(true)@Table(name="JPA_CUTOMERS")@Entitypublic class Customer {    private Integer id;    private String lastName;    private String email;    private int age;    private Date createdTime;    private Date birth;    public Customer() {    }    public Customer(String lastName, int age) {        super();        this.lastName = lastName;        this.age = age;    }    private Set<Order> orders = new HashSet<>();//  @TableGenerator(name="ID_GENERATOR",//          table="jpa_id_generators",//          pkColumnName="PK_NAME",//          pkColumnValue="CUSTOMER_ID",//          valueColumnName="PK_VALUE",//          allocationSize=100)//  @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")    @GeneratedValue(strategy=GenerationType.AUTO)    @Id    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    @Column(name="LAST_NAME",length=50,nullable=false)    public String getLastName() {        return lastName;    }    public void setLastName(String lastName) {        this.lastName = lastName;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Temporal(TemporalType.TIMESTAMP)    public Date getCreatedTime() {        return createdTime;    }    public void setCreatedTime(Date createdTime) {        this.createdTime = createdTime;    }    @Temporal(TemporalType.DATE)    public Date getBirth() {        return birth;    }    public void setBirth(Date birth) {        this.birth = birth;    }    //映射单向1-n的关联关系    //使用@OneToMany 映射单向1-n的关联关系    //使用@JoinColumn 来映射外键的名称    //可以使用@OneToMany 的 fetch 属性来修改加载策略    //可以使用@OneToMany 的 cascade 属性来修改默认的删除策略    @JoinColumn(name="CUSTOMER_ID")    @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE})    public Set<Order> getOrders() {        return orders;    }    public void setOrders(Set<Order> orders) {        this.orders = orders;    }    @Transient    public String getInfo(){        return "lastName: " + lastName + ", email: " + email;    }    @Override    public String toString() {        return "Customer [id=" + id + ", lastName=" + lastName + ", email="                + email + ", age=" + age + ", createdTime=" + createdTime                + ", birth=" + birth + "]";    }}

【2】双向多对一持久化操作

示例代码如下:

@Test    public void testOneToManyPersist(){        Customer customer = new Customer();        customer.setAge(18);        customer.setBirth(new Date());        customer.setCreatedTime(new Date());        customer.setEmail("mm@163.com");        customer.setLastName("MM");        Order order1 = new Order();        order1.setOrderName("O-MM-1");        Order order2 = new Order();        order2.setOrderName("O-MM-2");        //建立关联关系        customer.getOrders().add(order1);        customer.getOrders().add(order2);        order1.setCustomer(customer);        order2.setCustomer(customer);        //执行保存操作        entityManager.persist(customer);        entityManager.persist(order1);        entityManager.persist(order2);    }

这里先保存了1的一端。

控制台输出如下:

Hibernate:     insert     into        JPA_CUTOMERS        (age, birth, createdTime, email, LAST_NAME)     values        (?, ?, ?, ?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?     where        id=?Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?     where        id=?

如果先保存 n的一端呢,即先保存Order。

代码修改如下:

        entityManager.persist(order1);        entityManager.persist(order2);        entityManager.persist(customer);

控制台输出如下:

Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_CUTOMERS        (age, birth, createdTime, email, LAST_NAME)     values        (?, ?, ?, ?, ?)Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?,        ORDER_NAME=?     where        id=?Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?,        ORDER_NAME=?     where        id=?Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?     where        id=?Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?     where        id=?

综上可知:

若是双向 1-n 的关联关系, 执行保存时:

若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出2n 条 UPDATE 语句;若先保存 1 的一端, 则会多出 n 条 UPDATE 语句。

故在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句。

即,N的一端对应的表中使用外键关联1的一端,外键对应1的一端的表主键


修改Customer实体类如下:

//  @JoinColumn(name="CUSTOMER_ID")    @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE},mappedBy="customer")    public Set<Order> getOrders() {        return orders;    }

注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了。

先保存N的一端时控制台输出如下:

Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_CUTOMERS        (age, birth, createdTime, email, LAST_NAME)     values        (?, ?, ?, ?, ?)Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?,        ORDER_NAME=?     where        id=?Hibernate:     update        JPA_ORDERS     set        CUSTOMER_ID=?,        ORDER_NAME=?     where        id=?

先保存1 的一端时控制台输出如下:

Hibernate:     insert     into        JPA_CUTOMERS        (age, birth, createdTime, email, LAST_NAME)     values        (?, ?, ?, ?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)Hibernate:     insert     into        JPA_ORDERS        (CUSTOMER_ID, ORDER_NAME)     values        (?, ?)

综上,多对一持久化操作时,先保存1的一端。另外让n的一端维持关联关系,这样减少SQL执行,提高效率。


原创粉丝点击