Spring-Hibernate持久化不会导致插入 [英] Spring-Hibernate persist does not result in insert
问题描述
我试图实现一个简单的DAO。
我有一个Dao:
@Repository(iUserDao)
@Transactional(readOnly = true )
public class UserDao实现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();
返回true;
}
@Override
public boolean update(User user){
entityManager.merge(user);
entityManager.flush();
返回true;
}
@Override
public boolean delete(User user){
user = entityManager.getReference(User.class,user.getId());
if(user == null)
return false;
entityManager.remove(user);
entityManager.flush();
返回true;
}
以及一个实体:
@Entity
没执行。
@Table(name =users)
public class User {
private int id;
私人日期creationDate;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId(){
return id;
$ b $ 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;
$ b $ p $这些是appContext.xml:
` $ b $< bean id =entityManagerFactory
class =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
p:dataSource-ref =dataSourcep:jpaVendorAdapter-ref =jpaAdapter
p:persistenceUnitName =test>
< property name =loadTimeWeaver>
< bean
class =org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver/>
< / property>
< / bean>
< bean id =transactionManagerclass =org.springframework.orm.jpa.JpaTransactionManager
p:entityManagerFactory-ref =entityManagerFactory/>
class =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
p:database =MYSQLp:showSql =true/> ;
< bean class =org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor/>
< tx:annotation-driven />`
除非我调用<$ c在
persist()
或merge()
之后的$ c> flush()
为什么是这样?
如果我删除了@Transactional
,那么我在刷新时出现没有事务正在进行的错误,但是如果删除刷新没有插入到DB中。 >
解决方案它以这种方式工作,因为您将事务标记为只读
@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()可以参与有效的只读事务
$ b @Transactional
public void changeUserName(int id,String newName){
User u = dao.getById(ID); //或者不是
u.setName(newName); //更改将在交易结束时刷新
$ c $ <$ preI'm trying to implement a simple DAO. I have a Dao:
@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; }
And an entity:
@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; } }
Here's 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/>`
Unless I call
flush()
afterpersist()
ormerge()
the insert in not executed. Why is that? If I remove@Transactional
then I get error on "no transaction is in progress" on flush, but if remove flush nothing inserted to the DB.解决方案It works this way because you marked transaction as read only with
@Transactional(readOnly = true)
.As you can see, it doesn't make your transactions actually read-only since you still can persist changes by calling
flush()
manually. However, it disables automatic flush at the end of transaction, so that changes are not persisted without manual flush.You need either remove
readOnly
from class-level annotation, or override it on non-read-only methods with method-level annotations:@Override @Transactional(readOnly = false) public boolean save(User user) { ... }
Also note that transaction demarcation is usually applied to service layer methods, not to DAO methods. In particular, when writing DAO methods you actually don't know which transactions should be read-only, and which are not. This information is available only when designing service layer, as you can see in this example:
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 } }
这篇关于Spring-Hibernate持久化不会导致插入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!