当前位置: 首页 > 知识库问答 >
问题:

Hibernate,在出现异常问题后不要刷新会话

陶山
2023-03-14

我对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)

共有2个答案

裘兴思
2023-03-14

下面是您问题中的代码:

public long findUserId(Long id) {
    try {
        User user = UserSystemService.findByUserId(id);
        return user.getId();
    } catch (Exception e) {
        log("findUserId->id: " + id);
        throw e;
    }
}

您从数据库中获取记录并将其保存在实体中。然后,在catch块中,记录错误并重新引发异常。到目前为止还不错。但是,您正在刷新会话或在某处提交事务。你没有在问题中详细提到你的工作单元策略。

问题是,您试图刷新会话或在异常后提交事务。你不应该那样做。异常之后,您应该丢弃会话实例

为什么不在Hibernate异常后刷新?

工作单元是一个非常复杂的系统。它会跟踪所有加载实体的更改。Hibernate在保持实体的内存拷贝与底层RDBMS一致方面做得很好。刷新(或其他自动刷新方式)将使用内存中的更改更新RDBMS。当抛出Hibernate异常时,不能保证内存中的状态不再处于一致状态。这就是为什么Hibernate建议关闭会话,从头开始。

你在问题中提到的例外:

org.hibernate.AssertionFailure:com.test.app.model.Message条目中的null id(发生异常后不要刷新会话)

这并不是真正的例外。在此之前发生过真正的例外。您正在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;
    }

但是,正如我上面所说,这不是真正的解决方案。代码的另一部分出现错误。你必须诊断并修复它。我通常把放在会话中。flush()在我怀疑的代码块之后;这样,就很容易找到引发真正异常的确切代码行。

鲍俊杰
2023-03-14

最有可能的是,在调用findUserId()方法之前,您已经在其他地方抑制了一个异常。当您调用findUserId()时,会报告错误,因为在随后的调用中,Hibernate决定是时候对com.test.app.model.Message实体进行自动刷新了。

你应该考虑复习你的会话维护策略。如果是一个会话绑定到请求线程的常见web场景,而不是一个保持会话打开数小时的独立应用程序,那么修复将有所不同。

 类似资料:
  • 我试图在一个catch块中执行一些更新操作。冬眠例外ConstraintViolationException抛出如下 我正在使用Hibernate 4.3.6 这是我的UserRegistrationRequest实体 这是我的UserSecurityQuestions实体 尝试在catch块中执行更新时,我遇到以下错误 如果我抓住异常而不是约束违反异常看到下面的错误 有人能帮帮我吗,有没有更好的

  • 编辑:得到一个-1,你能解释一下为什么吗?我搜索了重复项,但没有找到任何重复项。 为我刚刚遇到的问题发布Q/a: 例外情况: org.hibernate.AssertionFailure: null id in xyz (在发生异常后不要刷新会话)

  • 我设置了一个非常基本的Grails 3 web应用程序,使用jdbc连接到PostgreSQL数据库。下面您可以找到< code>Cluster域类和专用服务的代码。 碰巧用同一个< code>slug参数调用了< code>createCluster方法两次: 导致以下异常 我以为违反一约束会被方法拦截,但显然我错了。好吧,所以我添加了一个try/catch,但它基本上没有效果,异常没有被包装,

  • 我有一个hibernate和JSF2应用程序进入部署服务器,突然抛出一个org。冬眠AssertionFailure:异常中的空id。我将立即提供堆栈跟踪和代码,但首先有四个重要问题: > 这只发生在部署服务器(Jboss)上 研究这一点,人们在尝试插入对象时似乎会出现这种错误。但是当我做一个简单的查询时,我得到了错误。(实际上,各种不同的查询,因为错误会随机出现在多个页面上。) 错误只会偶尔出现

  • 问题内容: 当取消注释时,我们将在第二种方法中获得en异常- 当作者。 为什么会这样呢? 问题答案: 问题似乎是Hibernate引发了一个异常(因此当前事务无效),但是随后您尝试在该会话中继续执行更多操作。 正确的方法是将您使用的测试分为2部分,一部分测试空作者,另一部分测试有效作者。 在生产代码(例如控制器)上,您需要重新启动操作(关闭事务,重新启动流程)才能继续。但是,考虑到游戏管理交易的方

  • 你好,我是PHP中的web开发人员,最近迁移到javaEE。我在mysql中创建表。这是第一类: . . . 这是我的第二节课: . . .