2013-03-08 49 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