2011-03-02 66 views
6

我試圖實現一個簡單的DAO。 我有一個道:Spring-Hibernate堅持不會導致插入

@Repository("iUserDao") 
@Transactional(readOnly = true) 
public class UserDao implements IUserDao { 
    private EntityManager entityManager; 

    @PersistenceContext 
    public void setEntityManager(EntityManager entityManager) { 
     this.entityManager = entityManager; 
    } 

    @Override 
    public User getById(int id) { 
     return entityManager.find(User.class, id); 
    } 

    @Override 
    public boolean save(User user) { 
     entityManager.persist(user); 
     entityManager.flush(); 
     return true; 
    } 

    @Override 
    public boolean update(User user) { 
     entityManager.merge(user); 
     entityManager.flush(); 
     return true; 
    } 

    @Override 
    public boolean delete(User user) { 
     user = entityManager.getReference(User.class, user.getId()); 
     if (user == null) 
      return false; 
     entityManager.remove(user); 
     entityManager.flush(); 
     return true; 
    } 

以及實體:

@Entity 
@Table(name = "users") 
public class User { 
    private int id; 
    private Date creationDate; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    public int getId() { 
     return id; 
    } 

    public User() { 
    } 

    public User(Date creationDate) { 
     this.creationDate = creationDate; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public Date getCreationDate() { 
     return creationDate; 
    } 

    public void setCreationDate(Date creationDate) { 
     this.creationDate = creationDate; 
    } 
} 

這裏的appContext.xml: `

<bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
     p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter" 
     p:persistenceUnitName="test"> 
    <property name="loadTimeWeaver"> 
     <bean 
       class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> 
    </property> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
     p:entityManagerFactory-ref="entityManagerFactory"/> 
<bean id="jpaAdapter" 
     class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" 
     p:database="MYSQL" p:showSql="true"/> 

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> 
<tx:annotation-driven/>` 

除非我persist()merge()在不插入後調用flush()執行。 這是爲什麼? 如果我刪除@Transactional,那麼在刷新時出現「沒有事務正在進行」的錯誤,但是如果刪除刷新沒有插入到DB中。

回答

10

是這樣工作的,因爲僅與@Transactional(readOnly = true)讀你標記事務。

正如您所看到的,它不會使您的交易實際爲只讀,因爲您仍然可以通過手動呼叫flush()來堅持更改。但是,它會在事務結束時禁用自動刷新功能,以便在沒有手動刷新的情況下更改不會持久。

你需要無論是從類級別的註釋去掉readOnly,或覆蓋非只讀方式與方法級別的註解:

@Override 
@Transactional(readOnly = false) 
public boolean save(User user) { ... } 

還要注意的是事務劃分通常適用於業務層的方法,而不是DAO方法。特別是,在編寫DAO方法時,您實際上不知道哪些事務應該是隻讀的,哪些不是。此信息在設計業務層時可用,你可以在這個例子中看到:

public class UserService { 
    @Autowired UserDAO dao; 

    @Transactional(readOnly = true) 
    public User getUserById(int id) { 
     return dao.getById(id); // getById() can participate in effectively read-only transaction 
    } 

    @Transactional 
    public void changeUserName(int id, String newName) { 
     User u = dao.getById(id); // Or not 
     u.setName(newName); // Change will be flushed at the end of transaction 
    } 
} 
+0

我已經改變了'@ Transactional'爲false,並且仍然沒有插入。關於交易標界,我謹記在心,謝謝。 刪除@ @ Transactional'也沒有幫助。 – AlexV 2011-03-02 14:59:49

+0

@AlexV:看起來很奇怪。你怎麼稱呼這些方法? – axtavt 2011-03-02 15:39:57

+0

不確定你說我是怎麼稱呼這些方法的。我有一個單元測試,我稱之爲DAO'save()'方法。 – AlexV 2011-03-02 16:03:28

1

嘗試事務傳播設置所需,並刪除所有flush(): -

@Repository("iUserDao") 
@Transactional(propagation=Propagation.REQUIRED) 
public class UserDao implements IUserDao { 
    ... 
}