使用@Transactional和Spring Data自定义方法

威姆·德布劳(Wim Deblauwe)

我正在使用Spring Data(通过Spring Boot 1.3.3)。我所有的存储库都有一个自定义方法来获取主键。例如:

@Transactional(readOnly=true)
@Repository
public interface UserRepository extends CrudRepository<User, UserId>, UserRepositoryCustom {
  User findByUsername(String username);
}

public interface UserRepositoryCustom {
  UserId nextId();
}

public class UserRepositoryImpl implements UserRepositoryCustom {
  public UserId nextId() {
    return new UserId( UUID.randomUUID() );
  }
}

@Transactional这里使用正确吗?或者我需要一个添加@TransactionalUserRepositoryImpl以及(可能与readOnly的设置与否)?

我问的原因是因为我无法解释 ObjectOptimisticLockingFailureException

org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class 
[com.company.project.domain.Game] with identifier [GameId{id=7968c30b-838f-424c-bfef-838de7028def}]: 
optimistic locking failed; nested exception is 
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction 
(or unsaved-value mapping was incorrect) : [com.company.project.domain.Game#GameId{id=7968c30b-838f-424c-bfef-838de7028def}]

这是在JMeter测试期间发生的。所调用的方法完全不会Game以任何方式更改实体。

我已将其添加到我的Game实体中进行调试:

@PreUpdate
public void preUpdate() {
    System.out.println("GAME UPDATED!! version = " + version);
    Thread.dumpStack();
}

这几次给出类似于以下的堆栈跟踪:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1329)
    at com.company.project.domain.Game.preUpdate(Game.java:85)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.hibernate.jpa.event.internal.jpa.EntityCallback.performCallback(EntityCallback.java:47)
    at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:112)
    at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.preUpdate(CallbackRegistryImpl.java:76)
    at org.hibernate.jpa.event.internal.core.JpaFlushEntityEventListener.invokeInterceptor(JpaFlushEntityEventListener.java:68)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.handleInterception(DefaultFlushEntityEventListener.java:342)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:293)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:160)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:231)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:102)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1227)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1293)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
    at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:495)
    at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getSingleResult(CriteriaQueryTypeQueryAdapter.java:71)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:206)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:78)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:100)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:91)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:462)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    at com.sun.proxy.$Proxy141.findByUsername(Unknown Source)
    at com.company.project.service.UserServiceImpl.findByUsername(UserServiceImpl.java:117)
    at com.company.project.service.UserServiceImpl.subtractCredits(UserServiceImpl.java:143)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    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:208)
    at com.sun.proxy.$Proxy154.subtractCredits(Unknown Source)
    at com.company.project.service.GameServiceImpl.subtractCreditsForPlacedShotsAndSave(GameServiceImpl.java:703)
    at com.company.project.service.GameServiceImpl.placeShotsOnGameWhenGameIsOpen(GameServiceImpl.java:641)
    at com.company.project.service.GameServiceImpl.placeShotsOnGame(GameServiceImpl.java:629)
    at com.company.project.service.GameServiceImpl.placeShots(GameServiceImpl.java:281)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    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:208)
    at com.sun.proxy.$Proxy164.placeShots(Unknown Source)
    at com.company.project.controller.front.FrontGameController.placeShots(FrontGameController.java:180)

仅查看与我的应用程序相关的内容,您会看到以下内容:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1329)
    at com.company.project.domain.Game.preUpdate(Game.java:85)
    at com.company.project.service.UserServiceImpl.findByUsername(UserServiceImpl.java:117)
    at com.company.project.service.UserServiceImpl.subtractCredits(UserServiceImpl.java:143)
    at com.company.project.service.GameServiceImpl.subtractCreditsForPlacedShotsAndSave(GameServiceImpl.java:703)
    at com.company.project.service.GameServiceImpl.placeShotsOnGameWhenGameIsOpen(GameServiceImpl.java:641)
    at com.company.project.service.GameServiceImpl.placeShotsOnGame(GameServiceImpl.java:629)
    at com.company.project.service.GameServiceImpl.placeShots(GameServiceImpl.java:281)
    at com.company.project.controller.front.FrontGameController.placeShots(FrontGameController.java:180)

因此,findByUsername似乎以某种方式触发了对不相关实体的更新Game

仅供参考:GameServiceImpl#placeShots也有一个@Transactional注释。我还尝试在Controller方法上添加这样的注释,但这并没有改变任何内容。

威姆·德布劳(Wim Deblauwe)

问题在于我使用@Transactional

我使用的是自定义的Hibernate UserType,它使用Jackson库将对象存储为JSON。Game对象具有使用此UserType的字段。该字段的类未实现equals()结果,Hibernate假定对象已更改,并在我的Game对象上进行了保存

正确实施之后equals(),问题就消失了。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

向Spring Data JPA添加自定义方法

来自分类Dev

Spring Data Couchbase自定义存储库方法

来自分类Dev

spring data cassandra react-自定义删除方法

来自分类Dev

使用自定义数据方法的自定义QStandardItemModel

来自分类Dev

Spring @Transactional方法和类

来自分类Dev

解析和验证自定义的方法

来自分类Dev

使用自定义main方法的Quarkus

来自分类Dev

使用自定义方法的骨干视图

来自分类Dev

对自定义对象使用Contains方法

来自分类Dev

使用spring-data-jpa的自定义ItemReader

来自分类Dev

使用spring-data-jpa的自定义ItemReader

来自分类Dev

spring-data-rest发布的自定义jpa存储库方法

来自分类Dev

实现Spring Data存储库的自定义方法并通过REST公开它们

来自分类Dev

自定义Spring Data REST以仅公开存储库中的选定方法

来自分类Dev

spring-data-rest发布的自定义jpa存储库方法

来自分类常见问题

使用自定义方法组合Where和OrderByDescending

来自分类Dev

使用自定义方法组合Where和OrderByDescending

来自分类Dev

使用 Spring Data JPA 自定义存储库方法将数据从 csv 加载到 mysql 表

来自分类Dev

如何使用角度元素定义自定义元素方法

来自分类Dev

编写自定义方法和自定义过滤器有什么区别?

来自分类Dev

Rails:使用自定义方法订购自定义模型

来自分类Dev

使用Spring Boot进行PreAuthorize和自定义AuthenticationFilter

来自分类Dev

Spring Data MongoDB自定义接口ConflictingBeanDefinitionException

来自分类Dev

Spring Data REST自定义查询集成

来自分类Dev

自定义Spring Data Rest @ManyToMany关系处理

来自分类Dev

自定义spring-data仓库后端

来自分类Dev

Spring Data MongoDB自定义接口ConflictingBeanDefinitionException

来自分类Dev

仓库的自定义实现Spring-Data-Cassandra

来自分类Dev

Spring Data - 带有自定义查询 (HQL) 的 PagingAndSortingRepository?

Related 相关文章

  1. 1

    向Spring Data JPA添加自定义方法

  2. 2

    Spring Data Couchbase自定义存储库方法

  3. 3

    spring data cassandra react-自定义删除方法

  4. 4

    使用自定义数据方法的自定义QStandardItemModel

  5. 5

    Spring @Transactional方法和类

  6. 6

    解析和验证自定义的方法

  7. 7

    使用自定义main方法的Quarkus

  8. 8

    使用自定义方法的骨干视图

  9. 9

    对自定义对象使用Contains方法

  10. 10

    使用spring-data-jpa的自定义ItemReader

  11. 11

    使用spring-data-jpa的自定义ItemReader

  12. 12

    spring-data-rest发布的自定义jpa存储库方法

  13. 13

    实现Spring Data存储库的自定义方法并通过REST公开它们

  14. 14

    自定义Spring Data REST以仅公开存储库中的选定方法

  15. 15

    spring-data-rest发布的自定义jpa存储库方法

  16. 16

    使用自定义方法组合Where和OrderByDescending

  17. 17

    使用自定义方法组合Where和OrderByDescending

  18. 18

    使用 Spring Data JPA 自定义存储库方法将数据从 csv 加载到 mysql 表

  19. 19

    如何使用角度元素定义自定义元素方法

  20. 20

    编写自定义方法和自定义过滤器有什么区别?

  21. 21

    Rails:使用自定义方法订购自定义模型

  22. 22

    使用Spring Boot进行PreAuthorize和自定义AuthenticationFilter

  23. 23

    Spring Data MongoDB自定义接口ConflictingBeanDefinitionException

  24. 24

    Spring Data REST自定义查询集成

  25. 25

    自定义Spring Data Rest @ManyToMany关系处理

  26. 26

    自定义spring-data仓库后端

  27. 27

    Spring Data MongoDB自定义接口ConflictingBeanDefinitionException

  28. 28

    仓库的自定义实现Spring-Data-Cassandra

  29. 29

    Spring Data - 带有自定义查询 (HQL) 的 PagingAndSortingRepository?

热门标签

归档