Spring @Transactional commit failures ; Deby + Eclipselink

混江龙づ霸主 提交于 2019-12-23 08:13:15

问题


The following is the spring config

Date Source

<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>

Entity manager config

<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>

The following is the code snippet used to persist entity

@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);
 }

}

Class :

@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; 
   }

  }

Log message:

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, CU_ORD, 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]

After some time the following error occurred in the same RWTransactionDao in some other REST imple methods

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 

Due to this error previous commit got rolled back but it not supposed to be.

Not sure what causes for this rollback.


回答1:


Derby locks single rows for INSERT statements, holding each row until the transaction is committed. (If there is an index associated with the table, the previous key is also locked.)

So for your problem, my understanding is your tried to INSERT two records to Derby in one transaction, so when your execute create(peTxn); the derby locks single rows and holding each row until the transaction is committed [ lockA ], then you try to execute create(fcTxn), it will try to obtain another single-row lock to INSERT a new record, but actually the transaction is not committed so the locks still holed [ lockA ].

So the solution is

call getEntityManager().refresh the transaction to commit the transaction when the first step finished. this will focus the SQL INSERT to database.

and suggest to use @Transactional in the service layer.




回答2:


The problem was due to PersistenceContextType.EXTENDED. I did two changes and problem got resolved.

  1. PersistenceContextType.EXTENDED changed to PersistenceContextType.TRANSACTION
  2. @Singleton changed to @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Component
    public class RWTransactionDao {
    
        @PersistenceContext(type = PersistenceContextType.TRANSACTION)
        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);
        }
    


来源:https://stackoverflow.com/questions/44539861/spring-transactional-commit-failures-deby-eclipselink

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!