java - 如何确保记录已添加到数据库中?

标签 java hibernate postgresql tapestry

我有两个应用程序:

  • 第一个向 postgresql 数据库插入一条记录(假设它的 id 等于 X)并通知第二个
  • 被通知的那个发送邮件给用户,但在此之前它检查id为X的记录(它包含在第一台机器的“通知消息”中)是否被插入到数据库中

在 99% 的情况下它运行良好,但有时第二台机器找不到具有给定 id 的记录。怎么可能?

在第一台机器上,我使用 hibernate 并将对象保存到数据库中:

objectDao.save(object);

然后发送消息:

publisher.sendObjectAddedMessage(user.getId(), ipSource.getIpAddress(), object.getId());

没什么好看的。我试图立即刷新 hibernate 状态或在发送消息之前稍等片刻,但随后出现了问题。

我的 PostgreSQL 版本是:

PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.7.2-5) 4.7.2, 64-bit

最佳答案

强烈建议您使用一些事件监听器调用 publisher.sendObjectAddedMessage()

即,您应该创建一个监听器,它将在任何对象被持久化后调用一个方法,以确保您的 sendObjectAddedMessage() 在实体被持久化之前绝不会被调用。

考虑这个例子:

我将保留这个简单的实体 Person.java 并将几个事件与该类相关联。每当保存此实体时,都会在提交负责此实体的事务之前和之后调用一些方法。

Person.java

@Entity
public class Person implements Serializable {
    @Id
    @GeneratedValue ( strategy = GenerationType.AUTO )
    int id;

    String name;

    //getters and setters below this
    ...
}

现在考虑我的 Main 类。您可以看到我已经创建了 AuditLogInterceptor 并将其与 session 相关联。

通过将此拦截器与session相关联,它会调用此拦截器的onSavepreFlushpostFlush等几个方法。这将确保在需要时始终调用这些方法。 (比如 postFlush 在实体保存前不会被调用)

测试.java

public class Test {
    public static void main(String[] args) {
        AuditLogInterceptor interceptor = new AuditLogInterceptor();

        Session session = HibernateUtil.getSessionFactory()
                .withOptions()
                .interceptor(interceptor)
                .openSession();
        interceptor.setSession(session);        

        Person p = new Person();
        p.setName("John Doe");

        session.getTransaction().begin();
        session.save(p);
        session.getTransaction().commit();
        session.close();
    }
}

这是主类 AuditLogInterceptor.java 的代码。它实现了hibernate的EmptyInterceptor接口(interface)。如您所知,在 Test.java 中,我们将 session 与该拦截器相关联。因此,它的重写方法将在多个事件(如保存、更新等)上被调用...

AuditLogInterceptor.java

package test;

import java.io.Serializable;
import java.util.Iterator;

import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Session;
import org.hibernate.type.Type;

public class AuditLogInterceptor extends EmptyInterceptor{
    Session session;

    public void setSession(Session session) {
        this.session=session;
    }

        @Override
    public boolean onSave(Object entity,Serializable id,
        Object[] state,String[] propertyNames,Type[] types)
        throws CallbackException {

        System.out.println("onSave");

        return false;

    }

    //called before commit into database
        @Override
    public void preFlush(Iterator iterator) {
        System.out.println("preFlush");
    }   

    //called after committed into database
        @Override
    public void postFlush(Iterator iterator) {
        System.out.println("postFlush");                        
    }   
}

现在是输出

Hibernate: drop table if exists hibernate_sequence
Hibernate: drop table if exists Person
Hibernate: create table hibernate_sequence (next_val bigint)
Hibernate: insert into hibernate_sequence values ( 1 )
Hibernate: create table Person (id integer not null, name varchar(255), primary key (id))
Feb 16, 2016 8:23:18 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
onSave
preFlush
Hibernate: insert into Person (name, id) values (?, ?)
postFlush   

如您所见,我们在 AuditLogInterceptor.java 的 colsole 上打印了 onSavepreFlushpostFlush

postFlush 期间,您可以调用您的 publisher.sendObjectAddedMessage()。在我看来,这将在 100% 的情况下正常工作 :)

要了解更多详情,请参阅this示例。

关于java - 如何确保记录已添加到数据库中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35417105/

相关文章:

mysql - SQL varchar 列长度的最佳实践

java - 需要帮助寻找全面的 netbeans 插件开发教程

java - 异常规范

java - 在不打印新行的情况下更新 java 控制台

java - 在 Hibernate 一对一关系中保存外键的问题

c# - 如何使用声明感知用户名/登录授权为我的 WCF 服务创建本地 STS?

用于泛型的 Java JSON 库

hibernate - Play Framework 和集合在模型类中的使用

java - 如何防止 Hibernate 刷新列表?

sql - 带有子字符串的棘手 SQL