我正在开发一个Spring boot 1.5.9.release和data-jpa 1.5.9.RELEASE的项目,我的项目中有一些实体,一个实体有@CreatedBy注释注入spring security authentication.getPrincipal()对象在插入或更新期间。它通过使用@EntityListener注释自动生成。
插入新行时一切都很好但是,当我更新我的持久化实体时,它会引发很多错误 - 大多数错误都会反复出现。
我的代码如下:
配置文件的一部分。
@EnableJpaAuditing(dateTimeProviderRef="dateTimeProvider")
@Configuration
public class CoreConfig {
@Bean
public AuditorAware<Member> auditorAware(){
return new AuditorAwareImpl();
}
@Bean
public DateTimeProvider dateTimeProvider(){
return new DateTimeProviderImpl();
}
}
AuditorAwareImpl
public class AuditorAwareImpl implements AuditorAware<Member>{
private static Logger logger = LoggerFactory.getLogger(AuditorAwareImpl.class);
@Autowired
private MemberService memberService;
@Override
public Member getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication == null){
return null;
}
String userEmail = authentication.getPrincipal().toString();
logger.info("JPA Audit username: [{}]", userEmail);
return memberService.findByEmail(userEmail);
}
}
导致错误堆栈的服务层。
@Transactional
@Service
public class GalleryReplyServiceImpl implements GalleryReplyService{
// .. skipped
@Override
public void editReply(GalleryReplyVO vo) {
GalleryReply reply = repository.findOne(Long.parseLong(vo.getReplySeq()));
reply.setMessage(vo.getMessage()); // this line is problematic.
}
}
用户权利:
@Entity
@Table(name="MEMBER", uniqueConstraints={
@UniqueConstraint(columnNames={"USER_SEQ"}),
@UniqueConstraint(columnNames={"USER_EMAIL"}),
@UniqueConstraint(columnNames={"NICKNAME"})
})
@Data
@NoArgsConstructor
@RequiredArgsConstructor(staticName="of")
public class Member implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="USER_SEQ", unique=true, nullable=false)
private Long userSeq;
@Email
@NotEmpty(message="이메일을 입력해주세요.")
@NonNull
@Column(name="USER_EMAIL", unique=true, nullable=false, length=50)
private String userEmail;
@NotEmpty(message="비밀번호를 입력해주세요.")
@NonNull
@Column(name="USER_PW", nullable=false, length=255)
private String userPw;
@Size(min=2, max=10)
@NonNull
@Column(name="NICKNAME", unique=true, nullable=false, length=20)
private String nickname;
@OneToOne(mappedBy="member", cascade=CascadeType.ALL)
private MemberSecurity security;
@Override
public String toString() {
return "Member [userSeq=" + userSeq + ", userEmail=" + userEmail + ", userPw=" + userPw + ", nickname="
+ nickname + "]";
}
// skipped...
}
以逻辑方式播放的实体(更新此实体会触发错误堆栈)。
@EntityListeners(AuditingEntityListener.class)
@Entity
@Table(name="GALLERY_REPLY", uniqueConstraints={
@UniqueConstraint(columnNames="REPLY_SEQ")
})
@Data
@NoArgsConstructor
@RequiredArgsConstructor(staticName="of")
public class GalleryReply implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="REPLY_SEQ", nullable=false, unique=true)
private Long replySeq;
@ManyToOne
@JoinColumn(name="GALLERY_SEQ", referencedColumnName="GALLERY_SEQ")
private Gallery gallery;
@ManyToOne
@JoinColumn(name="USER_SEQ", referencedColumnName="USER_SEQ")
@CreatedBy
private Member member;
@NonNull
@Lob
@Column(name="MSG", nullable=false)
private String message;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="CREATED_DT", nullable=false)
@CreatedDate
private Date createdDate;
@ManyToOne
@JoinColumn(name="REPLY_AT", referencedColumnName="REPLY_SEQ")
private GalleryReply replyAt;
@OneToMany(mappedBy="replyAt")
private Set<GalleryReply> subordinateds;
@Override
public String toString() {
return "GalleryReply [replySeq=" + replySeq + ", message=" + message + ", createdDate=" + createdDate + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GalleryReply other = (GalleryReply) obj;
if (replySeq == null) {
if (other.replySeq != null)
return false;
} else if (!replySeq.equals(other.replySeq))
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((replySeq == null) ? 0 : replySeq.hashCode());
return result;
}
}
错误堆栈是:
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] INFO c.m.c.core.util.AuditorAwareImpl - JPA Audit username: [musicovery12@naver.com]
2018-01-02 15:31:24 [http-nio-8080-exec-7] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/cookingstep2] threw exception [Request processing failed; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction] with root cause
java.lang.StackOverflowError: null
at org.hibernate.jpa.criteria.path.RootImpl.render(RootImpl.java:85)
at org.hibernate.jpa.criteria.path.RootImpl.renderProjection(RootImpl.java:91)
at org.hibernate.jpa.criteria.QueryStructure.render(QueryStructure.java:239)
at org.hibernate.jpa.criteria.CriteriaQueryImpl.interpret(CriteriaQueryImpl.java:292)
at org.hibernate.jpa.criteria.compile.CriteriaCompiler.compile(CriteriaCompiler.java:130)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:699)
at sun.reflect.GeneratedMethodAccessor103.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
at com.sun.proxy.$Proxy123.createQuery(Unknown Source)
at sun.reflect.GeneratedMethodAccessor103.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy123.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:205)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:155)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:86)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:190)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:208)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:87)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:499)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
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:282)
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:115)
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.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy132.findByUserEmail(Unknown Source)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl.findByEmail(MemberServiceImpl.java:61)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl$$FastClassBySpringCGLIB$$3b245c15.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
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:282)
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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl$$EnhancerBySpringCGLIB$$b2806f0.findByEmail(<generated>)
at com.musicovery12.cookingstep2.core.util.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:32)
at com.musicovery12.cookingstep2.core.util.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:1)
at org.springframework.data.auditing.AuditingHandler.touchAuditor(AuditingHandler.java:176)
at org.springframework.data.auditing.AuditingHandler.touch(AuditingHandler.java:155)
at org.springframework.data.auditing.AuditingHandler.markModified(AuditingHandler.java:134)
at org.springframework.data.jpa.domain.support.AuditingEntityListener.touchForUpdate(AuditingEntityListener.java:96)
at sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.jpa.event.internal.jpa.ListenerCallback.performCallback(ListenerCallback.java:35)
at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:94)
at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.preUpdate(CallbackRegistryImpl.java:68)
at org.hibernate.jpa.event.internal.core.JpaFlushEntityEventListener.invokeInterceptor(JpaFlushEntityEventListener.java:51)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.handleInterception(DefaultFlushEntityEventListener.java:325)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:276)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:143)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1319)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:529)
at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getSingleResult(CriteriaQueryTypeQueryAdapter.java:54)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:208)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:87)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:499)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
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:282)
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:115)
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.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy132.findByUserEmail(Unknown Source)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl.findByEmail(MemberServiceImpl.java:61)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl$$FastClassBySpringCGLIB$$3b245c15.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
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:282)
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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.musicovery12.cookingstep2.core.service.MemberServiceImpl$$EnhancerBySpringCGLIB$$b2806f0.findByEmail(<generated>)
at com.musicovery12.cookingstep2.core.util.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:32)
at com.musicovery12.cookingstep2.core.util.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:1)
at org.springframework.data.auditing.AuditingHandler.touchAuditor(AuditingHandler.java:176)
at org.springframework.data.auditing.AuditingHandler.touch(AuditingHandler.java:155)
at org.springframework.data.auditing.AuditingHandler.markModified(AuditingHandler.java:134)
at org.springframework.data.jpa.domain.support.AuditingEntityListener.touchForUpdate(AuditingEntityListener.java:96)
at sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.jpa.event.internal.jpa.ListenerCallback.performCallback(ListenerCallback.java:35)
at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:94)
at org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl.preUpdate(CallbackRegistryImpl.java:68)
at org.hibernate.jpa.event.internal.core.JpaFlushEntityEventListener.invokeInterceptor(JpaFlushEntityEventListener.java:51)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.handleInterception(DefaultFlushEntityEventListener.java:325)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:276)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:143)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1319)
... over and over and ends by some time.
我认为这是实体的双向原因。有什么帮助吗?