简体   繁体   English

@Transactional的范围

[英]Scope of @Transactional

For example, I have a code something like this 例如,我有这样的代码

@Transactional(propogation=PROPOGATION.REQUIRED)
public class codeForTest {

  public void doSomethins(){
    User user = userRepository.finduserById(userId);
    updateUserDetails(user);
    updateFewOtherDetails(user);
  }

}

public class DifferentClass{

  @Transactional(propogation=PROPOGATION.REQUIRED)
  updateUserDetails() {
    //UPDATES user object
  }

}

I am getting the following in couple of instances with the above logic. 在上述几种情况下,我得到了以下几个例子。 I don't get an error in local machine. 我在本地计算机上没有收到错误。 My question is if updateUserDetails() will commit the transaction and when updateFewOtherDetails() is executed, since the transaction is committed, is it throwing the exception ? 我的问题是,如果updateUserDetails()将提交事务,并且在执行updateFewOtherDetails()时,由于提交了事务,是否会引发异常? I doubt if that is creating the problem since where are annotating it with @Transactional (propogation= PROPOGATION.REQUIRED) 我怀疑这是否在造成问题,因为在哪里用@Transactional注释(传播= PROPOGATION.REQUIRED)

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.checkRowCounts(BatchingBatch.java:151)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:128)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:111)
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:163)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:226)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:482)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
... 130 common frames omitted
 Wrapped by: org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:297)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:221)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy1125.createUserSession(Unknown Source)

You are using JPA (Hibernate) with optimistic locking . 您正在使用具有乐观锁定功能的JPA(休眠)。 The actual exception: 实际的例外:

org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; org.springframework.orm.ObjectOptimisticLockingFailureException:批处理更新从更新[0]返回了意外的行数; actual row count: 0; 实际行数:0; expected: 1; 预期:1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; 嵌套的异常是org.hibernate.StaleStateException:批处理更新从更新[0]返回了意外的行数; actual row count: 0; 实际行数:0; expected: 1 预期:1

means that while your transaction was running another transaction updated the same rows, Hibernate detected their stale state and rolled back current transaction to avoid data consistency problems. 意味着当您的事务正在运行时,另一个事务更新了相同的行,Hibernate检测到它们的陈旧状态并回滚当前事务以避免数据一致性问题。 This can happen with optimistic locking on a contended resource, but it's not bad because due to rollback the data is still consistent in the database. 乐观地锁定竞争的资源可能会发生这种情况,但这并不坏,因为由于回滚,数据库中的数据仍然保持一致。

There are few ways you can resolve this: 有几种方法可以解决此问题:

  • Retry the logic that caused ObjectOptimisticLockingFailureException and hope that next transaction won't be contended. 重试导致ObjectOptimisticLockingFailureException的逻辑,并希望不会竞争下一个事务。
  • Relax transaction boundaries to perform a few smaller and faster transaction 放宽交易边界,以执行一些更小,更快的交易
  • Queue updates in application logic 应用程序逻辑中的队列更新

Both the methods will be executed in bounds of single transaction, once they both marked @Transactional . 两种方法都标记为@Transactional ,将在单个事务的边界内执行。

user object was loaded in bounds of different transaction or taken from cache, in a case .finduserById() uses the one. 如果.finduserById()使用一个对象, .finduserById() user对象加载到不同事务的边界中或从缓存中.finduserById()

Make sure you've marked @Transactional second .updateFewOtherDetails() method too. 确保您也已标记@Transactional第二个.updateFewOtherDetails()方法。

With propagation REQUIRED the transaction won't commit until the end of caller sequence. REQUIRED传播的情况下,直到调用者序列结束,事务才提交。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM