【问题标题】:Spring @Transactional commit failures ; Deby + EclipselinkSpring @Transactional 提交失败; Deby + Eclipselink
【发布时间】:2017-11-16 07:34:59
【问题描述】:

以下是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>

下面是sn-p用来持久化实体的代码

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

一段时间后,在其他一些 REST impl 方法中,相同的 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 

由于这个错误,之前的提交被回滚了,但它不应该被回滚。

不确定导致此回滚的原因。

【问题讨论】:

  • 您是否有足够的开放连接到数据库?连接池?
  • @tak3shi 使用 dbcp2.BasicDataSource 和默认连接池大小
  • 表锁,理想情况下我们不应该看到应用程序持有的表锁,因为它们不应该运行 DDL 操作。是否运行任何 DDL 操作,如备份、在数据库上创建索引和持有表锁?
  • 你根本没有在这个交易中展示你在做什么。在 EclipseLink 中打开日志以查看它在锁定超时之前发出的 SQL,并检查您的方法,因为如果您不显示您在 createNewRWRetailTransaction 和任何其他使用 JPA 的调用中所做的事情,我们将无能为力。
  • Spring 应该重用相同的 EntityManager 和数据库连接,所以它不应该自己锁定 - 但我不熟悉 Spring,而且你没有显示任何日志,所以我不能吨说。甚至错误堆栈跟踪也可能会告诉您错误来自何处,并指出在您的方法认为它已成功返回后它为何回滚。顺便问一下,捕获这个异常的 RWCompartmentRestExceptionMapper 类是什么?

标签: java spring jpa eclipselink derby


【解决方案1】:

Derby 为 INSERT 语句锁定单行,保留每一行直到事务提交。 (如果有与表关联的索引,则前一个键也被锁定。)

所以对于您的问题,我的理解是您尝试在一个事务中插入两条记录到 Derby,因此当您执行 create(peTxn); 时,derby 会锁定单行并保留每一行,直到事务完成提交[lockA],然后你尝试执行create(fcTxn),它会尝试获取另一个单行锁INSERT一条新记录,但实际上该事务并没有已提交,因此锁仍然有孔 [ lockA ]。

所以解决办法是

当第一步完成时调用getEntityManager().refresh事务来提交事务。这会将 SQL INSERT 集中到数据库。

并建议在服务层使用@Transactional

【讨论】:

  • peTxn 和 FcTxn 必须一起提交。我们在持久化期间不使用刷新
  • @vels4j 你可以试一试,如果解决方案真的解决了你的问题,那么接下来,你可以添加额外的代码来保持一致性
  • 这里的“事务”似乎是一个实体,代码是试图在同一个数据库事务中插入两个实体。如果连接正确应该没问题
【解决方案2】:

问题是由PersistenceContextType.EXTENDED 引起的。我做了两个更改,问题得到了解决。

  1. PersistenceContextType.EXTENDED改为PersistenceContextType.TRANSACTION
  2. @Singleton 更改为 @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);
        }
    

【讨论】:

    猜你喜欢
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2013-04-24
    • 2011-07-15
    • 2020-01-31
    • 2021-03-20
    相关资源
    最近更新 更多