我在Hibernate和JPA存储库实现方面遇到问题。
我收到有关以下内容的错误:
“发生异常后不要刷新会话”
这是从节开始的->保存模型之前,先检查数据库中是否存在。
消息表:
@Entity
@Table(name="message")
public class Message {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "type")
private MessageType type;
@Column(name = "date")
private Timestamp date;
@Column(name = "message")
private String message;
@ManyToOne(cascade= {CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.DETACH, CascadeType.REFRESH})
@JoinColumn(name="user_id")
private User User;
//constructor, empty constructor, getter & setter
}
用户表:
@Entity
@Table(name = "user")
public class User {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "city")
private String city;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "user",
cascade = {CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.DETACH, CascadeType.REFRESH})
private List<Message> message;
//constructor, empty constructor, getter & setter
}
服务:
@Service
@Transactional
public class MessageUserDataService implements MessageUserService {
public void saveToDatabase(String data, String type, String message) {
long userId;
if (data.containsKey(userCode)) {
userId = findUserId(userCode);
}
MessageData messageData = new MessageData();
User user = UserSystemService.findByUserId(id);
messageData.setUser(user);
messageData.setType(type);
messageData.setMessage(message);
messageDataService.save(messageData);
}
public long findUserId(Long id) {
try {
User user = UserSystemService.findByUserId(id);
return user.getId();
} catch (Exception e) {
log("findUserId->id: " + id);
throw e;
}
}
可能是问题所在-这是异常。会话仍处于打开状态。当然,我在使用事务性注释。
执行日志:
29.07.2019 21:43:12org.hibernate.AssertionFailure: null id in com.test.app.model.Message entry (don't flush the Session after an exception occurs)
29.07.2019 21:43:12 at org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:60)
29.07.2019 21:43:12 at org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:175)
29.07.2019 21:43:12 at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:135)
29.07.2019 21:43:12 at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
29.07.2019 21:43:12 at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
29.07.2019 21:43:12 at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
29.07.2019 21:43:12 at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1398)
29.07.2019 21:43:12 at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1483)
29.07.2019 21:43:12 at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1445)
29.07.2019 21:43:12 at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
29.07.2019 21:43:12 at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1463)
29.07.2019 21:43:12 at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:214)
29.07.2019 21:43:12 at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)
29.07.2019 21:43:12 at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)
29.07.2019 21:43:12 at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
29.07.2019 21:43:12 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:590)
29.07.2019 21:43:12 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
29.07.2019 21:43:12 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
29.07.2019 21:43:12 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
29.07.2019 21:43:12 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
29.07.2019 21:43:12 at com.test.app.model.service.UserService.findUserId(UserService.java:14)
答案 0 :(得分:1)
在调用catch
方法之前,很可能您已经抑制了其他地方的findUserId()
块异常。调用findUserId()
时会报告此错误,因为这是Hibernate决定在com.test.app.model.Message
实体上auto-flush的时间的后续调用。
您应该考虑查看会话维护策略。如果是通常的Web场景,会话绑定到请求线程,则修复方法会有所不同;与之相比,如果您使用一个独立的应用程序将会话保持打开状态数小时,则此修复方法将有所不同。
答案 1 :(得分:1)
从下面的问题代码中:
public long findUserId(Long id) {
try {
User user = UserSystemService.findByUserId(id);
return user.getId();
} catch (Exception e) {
log("findUserId->id: " + id);
throw e;
}
}
您正在从数据库中获取记录并将其保存在实体中。然后,在catch
块中,您正在记录错误并重新引发异常。目前很好。但是随后,您将刷新会话或在某处提交事务。您尚未在问题中详细提及工作单位策略。
问题是,您试图以某种方式在异常之后刷新会话或提交事务。你不应该那样做。发生异常后,您应该丢弃该会话实例。
为什么在休眠异常后不Flush
?
工作单元是非常复杂的系统。它跟踪所有已加载实体的更改。 Hibernate所做的出色工作可将此保留在内存中实体副本与基础RDBMS保持一致。 Flush
(或其他自动刷新方式)将使用内存更改来更新RDBMS。引发Hibernate异常时,不能保证此内存中状态不再处于一致状态。这就是为什么Hibernate建议关闭会话并从头开始的原因。
您提到的异常:
org.hibernate.AssertionFailure:com.test.app.model.Message条目中的ID为null(发生异常后请勿刷新Session)
这不是真正的例外。真正的例外发生在那之前。您正在catch
块中记录异常。您的catch
块应在发生异常的情况下关闭会话-如果未提交,它也会回滚事务。
如果出现异常,则应关闭会话。由于没有太多有关如何在代码中实现会话的信息,因此下面仅作为示例:
catch (Exception e) {
log("findUserId->id: " + id);
session.close();//<--close the session. This will also rollback the transaction if not committed
throw e;
}
但是,如上所述,这不是真正的解决方案。您的代码其他部分出现错误。您必须诊断并修复它。我通常将session.flush()
放在我怀疑的代码块后面;这样,查找引发实际异常的确切代码行变得容易。