以下是
spring配置
日期来源
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="${rwos.dataSource.driverClassName}" /> <property name="url" value="${rwos.dataSource.url}" /> <property name="username" value="${rwos.dataSource.user}" /> <property name="password" value="${rwos.dataSource.password}" /> </bean>
实体经理配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="persistenceUnitManager" class="org.springframework.data.jpa.support.MergingPersistenceUnitManager"> <property name="defaultDataSource" ref="dataSource"/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerfactorybean"> <property name="persistenceUnitManager" ref="persistenceUnitManager"/> <property name="persistenceUnitName" value="com.retailwave.rwos_rwos-data-pojo_jar_4.0.0PU"/> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" lazy-init="true"> <property name="entityManagerFactory" ref="entityManagerFactory"/> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> </beans>
以下是用于持久化实体的代码段
@Singleton @Component public class RWTransactionDao { @PersistenceContext(type = PersistenceContextType.EXTENDED) private EntityManager em; @Override protected EntityManager getEntityManager() { return em; } @Transactional public void createOrderTxns(RWRetailTransaction peTxn,RWRetailTransaction fcTxn) { create(peTxn); create(fcTxn); log.debug("Committed Transaction : {} ",peTxn.displayString()); log.debug("Committed Transaction : {} ",fcTxn.displayString()); } @Transactional public void create(T entity) { getEntityManager().persist(entity); } }
分类:
@Component @Path("/") public class RWTransactionREST { @Inject private RWTransactionDao rWTransactionDao; @POST @Produces(MediaType.APPLICATION_JSON) @Path("txns/sales") public RWResponse createPurchaseTransaction(RWRetailTransaction peTxn,RWRetailTransaction fcTxn) { rWTransactionDao.createOrderTxns(peTxn,fcTxn); builder.status(RWStatus.OK); RWResponse response = builder.build(); log.info("Returning.. {}",response); return response; } }
记录消息:
2017-06-14 10:49:51,453 DEBUG [qtp592179046-13] - Committed Transaction : RWRetailTransaction[609,CU_ORD,RTCO-609-17-11193,2017-06-14 10:49:51.431] 2017-06-14 10:49:51,453 DEBUG [qtp592179046-13] - Committed Transaction : RWRetailTransaction[509,RTCO-509-17-11193,2017-06-14 10:49:51.444] 2017-06-14 10:49:51,463 INFO [qtp592179046-13] RWTransactionREST - Returning.. Response[1000:Order has been created successfully,Transaction Id : RTCO-609-17-11193]
一段时间后,在其他一些REST实现方法中,同一个RWTransactionDao中发生了以下错误
2017-06-14 10:51:24,199 ERROR [qtp592179046-16] com.retailwave.rwos.compartment.rest.exception.RWCompartmentRestExceptionMapper - Exception caught at Mapper : Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.sqlTransactionRollbackException: A lock could not be obtained within the time requested
由于此错误,先前的提交已回滚但不应该回滚.
不确定导致此回滚的原因.
解决方法
Derby为INSERT语句锁定单行,保持每一行直到提交事务. (如果存在与表关联的索引,则前一个键也会被锁定.)
所以对于你的问题,我的理解是你试图在一个事务中将两条记录INSERT到Derby,所以当你执行create(peTxn); derby锁定单行并保持每一行直到事务提交[lockA],然后你尝试执行create(fcTxn),它会尝试获取另一个单行锁来INSERT一条新记录,但实际上该事务不是因此锁仍然锁定[lockA].
所以解决方案是
调用getEntityManager().刷新事务以在第一步完成时提交事务.这将把sql INSERT的重点放在数据库上.
并建议在服务层使用@Transactional.