在调用另一个dao本机查询后,我遇到了事务自动提交的问题。
service和dao都签名为@Transactional。
我在这里做错了什么?
Spring 4.2.x
Hibernate 5.1.0
Atomikos 3.9.3
这是我的设置:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="jtaPlatformAdapter" class="com.xxx.JtaPlatformAdapter">
<property name="jtaTransactionManager" ref="transactionManager" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" id="atomikosTransactionManager" init-method="init">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionImp" id="atomikosUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="datasouce" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
...
</bean>
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="JPAVendorAdapter">
...
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf" depends-on="transactionManager,jtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.xxx.server"/>
<property name="dataSource" ref="datasouce" />
<property name="persistenceUnitName" value="pun" />
<property name="jpaVendorAdapter" ref="JPAVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="on_close" />
<entry key="hibernate.transaction.jta.platform" value="com.xxx.server.JtaPlatformAdapter" />
</map>
</property>
</bean>
的persistence.xml
<persistence-unit name="pun" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
服务
@Transactional
@Scope("prototype")
public synchronized void save(EntityObj model) throws Exception {
model.setX(30);
model.setY(40);
EntityObj oldModel = entityObjDAO.findById(model.getId());
// after call findById, the model had been commit to DB
...
...
...
entityObjDAO.store(model); // this will call entityManager.merge(model)
entityObjDAO.flush();
}
DAO
@Transactional
public EntityObj findById(String id) {
EntityObj model = null;
String sql = "select id,x,y from EntityObj where id = :id"; // this is a native sql query
Query query = this.entityManager.createNativeQuery(sql);
query.setParameter("id", id);
Object[] rs = (Object[]) query.getSingleResult();
if (rs != null) {
model = new EntityObj();
model.setId(id);
model.setX(rs[1] == null ? null : (Integer) rs[1]);
model.setY(rs[2] == null ? null : (Integer) rs[2]);
}
return model;
}
谢谢!
答案 0 :(得分:1)
如果您在代码中使用@Transactional
,Spring会为您的Dao对象(包装器)创建一个代理对象。
如果您的应用程序正在运行,它看起来像这样:
public EntityObj proxyMethodForFindById(String id) {
try {
// 1. start transaction
startTransaction();
// 2. execute your code
return yourDaoObject.findById(id);
} finally { // [!] PSEUDO CODE: NO EXCEPTION HANDLING
// commit transaction
commitTransaction();
}
}
那么你的代码会发生什么?
您的保存方法也标记为@Transactional
。因此,如果您通过设置更改对象:
model.setX(30);
model.setY(40);
Spring创建了两个代理。一个用于Service
,一个用于Dao
。在findById
- 交易结束时,此更改将被提交。嵌套事务是关键字。
您应该删除@Transaction
- 方法中的findById
或更好的整个Dao对象。 Service
应该是事务性的,而不是Dao层。