2013-03-08 77 views
0

我有支付实体双向ManyToOne releshionship帐户。JPA如何坚持双向ManyToOne父母

@Table(name="account") 
public class Account implements Serializable { 

    //bi-directional many-to-one association to Payment 
    @OneToMany(mappedBy="account",fetch=FetchType.EAGER) 
    private List<Payment> payments; 

@Table(name="payment") 
public class Payment implements Serializable { 

    //bi-directional many-to-one association to Account 
    @ManyToOne(cascade={CascadeType.MERGE},fetch=FetchType.EAGER) 
    @JoinColumn(name="idAcc") 
    private Account account; 

账户实体被持续存在。我看到在浏览器和数据库有关的信息:

帐户[idAcc = 475,帐户= 123456789,isLock = N,其余= 10000.5]

然后,我需要坚持的孩子(支付实体)并同时更改帐户实体(更改帐户休息)。我使用这个代码。

public class GenericDaoImpl<T> implements GenericDao<T> { 

     protected Class<T> type; 
     protected EntityManagerFactory emf = null; 

     public GenericDaoImpl(Class<T> type, EntityManagerFactory emf) { 
      this.emf = emf; 
      this.type = type;  
     } 

     @Override 
     public void create(T entity) throws Exception { 
      EntityManager em = null; 
      try { 
       em = getEntityManager(); 
       em.getTransaction().begin(); 
       em.persist(entity); 
       em.getTransaction().commit(); 
      } 
... 
@Override 
    public T findById(String id) { 
     EntityManager em = getEntityManager(); 
      try { 
       Query query = em.createNamedQuery(type.getSimpleName()+".findByName"); 
       query.setParameter("id", id); 
       return (T)query.getSingleResult(); 
      } finally { 
       em.close(); 
      } 
    } 

而且

daoPayments = new GenericDaoImpl(Payment.class,factory); 
      Payment payment = null; 
       try { 
        payment = new Payment(); 
        payment.setDescription("Shop 'Pirasmani'"); 
        payment.setSumm(50.25); 
         Account account = (Account)daoAccount.findById(listAccount.get(0).getIdAcc()); 
         account.setRest(account.getRest()-payment.getSumm()); 
         payment.setAccount(account); 
         account.getPayments().add(payment); 

        daoPayments.create(payment); 
        //print result 
        Payment paymentMerged = (Payment)daoPayments.read(payment); 
        out.println(paymentMerged.toString()+"<br>"); 

然后我看到在占其余更改了浏览器:

付款[idPmnt = 91,说明=店 'Pirasmani',SUMM = 50.25, account = Account [idAcc = 475,account = 123456789,isLock = N, rest = 9950.25]]

但是在数据库中账户休息没有变化。钢= 10000.5。 我在做什么错?谢谢。

回答

2

您不应该在DAO方法中启动和停止事务。在最后一节的所有代码应该是在一个单一的交易,这将让你

  • 工作在连接实体,并拥有账户的所有更改会自动持续
  • 上删除不必要的cascade={CascadeType.MERGE}协会
  • 使数据库处于一致状态,而不是像现在一样,在创建付款但其余未减少的状态下(这就是我们首先使用交易的原因)。

这就是说,你坚持付款。为什么会导致账户的任何修改?您拥有的唯一级联是MERGE,并且您没有在代码中进行任何合并。

+0

感谢您的快速响应。为什么我不应该在DAO方法中启动和停止事务?我在JPA的例子中发现了DAO的标准代码。所以我为所有实体使用一个通用的DAO.class。而且,据我所知,JPA注释使用这个通用的DAO为我打了个洞。我认为我的注释有问题。有没有其他方式如何解决我的问题,而无需更改DAO或我需要为每个实体编写特定的DAO? – Foontik 2013-03-08 16:03:17

+0

因为交易的重点是保证ACIDity(原子性,连贯性,隔离性,耐久性)。您希望您的数据保持一致:或者创建了付款,其余的数据都减少了,或者这两个操作都没有完成。这就是交易被使用的原因。如果每个操作都是在单个事务中完成的,那么您的数据库不会保持一致状态(正如您刚刚看到的那样)。事务应该由服务层划分,而不是由DAO层划分。 – 2013-03-08 16:06:56

+0

好的,谢谢,我明白了,但如果我在服务层中移动了交易,我的老师不会很高兴。我知道什么是ACID。我曾经想过,如果我改变第一个实体和第二个实体(由Cascade注释映射)比坚持第一个实体,所以这会自动改变其他实体的单个事务。这不是JPA的主要特性吗?而且我知道它的效果很好,例如,如果您创建父项并添加他的新子项,那么对于“OneToMany”,只需坚持父项。在这种情况下,不需要编码Cascade注释。全部存储在单个事务中。 – Foontik 2013-03-08 17:12:39