2016-02-15 96 views
2

我有兩個應用:如何確保記錄已添加到數據庫中?

  • 第一個插入一條記錄到PostgreSQL數據庫(假設它的id等於X),並通知其被通知發送郵件給用戶的第二個
  • 之一,但在此之前,它會檢查是否具有ID X的記錄(它被包含在從第一機器的「通知信息」中)被插入到數據庫中

在99%情況下,它工作得很好,但有時所述第二機無法找到具有給定ID的記錄。怎麼可能?

在我使用Hibernate和對象保存到這樣的數據庫中的第一臺機器的側面:

objectDao.save(object); 

,然後發送消息:

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

沒什麼特別的。我試圖在發送消息之前立即刷新休眠或稍等一會,但事件發生後就會出現問題。

我的PostgreSQL的版本是:

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

如果您在發送該消息之前增加了時間,那麼可以嗎?該記錄出現在數據庫或缺少?或者在發送消息後註冊會出現在數據庫中? –

+0

在第二臺機器上,我實現了「三次嘗試」機制(超時),這有時可以幫助,但並不經常。 – y434y

回答

1

我們強烈建議您使用一些事件偵聽器調用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並將它與會話相關聯。

通過將此攔截器與會話相關聯,它將調用攔截器的幾種方法,如onSavepreFlushpostFlush方法。這將確保在需要時總是調用這些方法。 (如postFlush不會被保存實體之前調用)

Test.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的代碼。它實現了休眠的EmptyInterceptor接口。正如您在Test.java中所瞭解的那樣,我們將會話與此攔截器關聯。因此,它的覆蓋方法將被稱爲在幾個事件,如保存,更新等..

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 

正如你可以看到,我們的印刷onSave輸出,preFlushpostFlush,在大底AuditLogInterceptor.java

postFlush期間,您可以撥打publisher.sendObjectAddedMessage()。在我看來,這將在所有情況下100%正常工作:)

要了解更多詳情,請參閱this示例。

相關問題