2011-05-11 4 views
4

이것은 나에게 당황 스럽다. 나는 단서를 찾기 위해 수많은 포럼을 수색했다. postFlush 메소드에서, 새로운 세션을 사용하여 새로운 절전 모드 (v 3.3 - v.3.5 시도) 세션을 연다. 연결 풀링을 위해 c3p0 v. 0.9를 사용합니다. 새 트랜잭션을 시작하고 auditLog 객체를 저장 한 다음 트랜잭션을 커밋합니다. 이것은 모든 엔티티가 하나를 제외하고 아름답게 작동합니다. ChemoRegimen 엔티티를 삭제 한 후 auditLog를 커밋하려고 시도하면 응용 프로그램이 중지됩니다 (이 또한 생성 및 업데이트와 함께 발생합니다). (이것은 스윙 응용 프로그램입니다) 어떤 예외가 발생되지 않지만 스레드를 일시 중단에 나는 다음과 같은 스택 추적을 찾을 :Hibernate Interceptor를 사용하는 감사 로깅이 SocketInputStream.socketRead0에서 중단되는 이유는 무엇입니까?

Thread [AWT-EventQueue-0] (Suspended) 
SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available [native method]  
SocketInputStream.read(byte[], int, int) line: 129 
VisibleBufferedInputStream.readMore(int) line: 145 
VisibleBufferedInputStream.ensureBytes(int) line: 114 
VisibleBufferedInputStream.read() line: 73 
PGStream.ReceiveChar() line: 274  
QueryExecutorImpl.processResults(ResultHandler, int) line: 1660 
QueryExecutorImpl.execute(Query[], ParameterList[], ResultHandler, int, int, int) line: 407 
Jdbc4PreparedStatement(AbstractJdbc2Statement).executeBatch() line: 2737  
NewProxyPreparedStatement.executeBatch() line: 1723 
BatchingBatcher.doExecuteBatch(PreparedStatement) line: 70 
BatchingBatcher(AbstractBatcher).executeBatch() line: 268 
ActionQueue.executeActions(List) line: 266 
ActionQueue.executeActions() line: 167 
DefaultFlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 321 
DefaultFlushEventListener.onFlush(FlushEvent) line: 50 
SessionImpl.flush() line: 1027 
SessionImpl.managedFlush() line: 365  
JDBCTransaction.commit() line: 137 **[This is where I commit the auditLog]** 
MomsInterceptor.postFlush(Iterator) line: 254 
DefaultFlushEventListener(AbstractFlushingEventListener).postFlush(SessionImplementor) line: 375  
DefaultFlushEventListener.onFlush(FlushEvent) line: 51 
SessionImpl.flush() line: 1027 
SessionImpl.managedFlush() line: 365  
JDBCTransaction.commit() line: 137 
HibernateDAO.makeTransient(Entity) line: 119  
ChemoServices.deleteChemoRegimen(ChemoRegimen, String, Session) line: 290 

내가 9.0 JDBC4 드라이버와 백엔드로 PostgreSQL의 8.4을 사용하고 있습니다.

[첫째, chemo_regimen가 삭제]

2011-05-11 12:19:06 CDT moms postgres LOG: 00000: execute <unnamed>: delete from moms_chemo_regimen where crxreg_id=$1<BR> 

....
[계단식 삭제의 많은] : [괄호 내 의견]을 postgresql.log 쇼
...
[그럼, 내 트랜잭션 인터셉터 세션에서 시작]

,691,363,210
2011-05-11 12:19:06 CDT moms postgres LOG: 00000: execute S_1: BEGIN 
2011-05-11 12:19:06 CDT moms postgres LOG: 00000: execute <unnamed>: select nextval ('moms_patient_change_log_seq') 


2011-05-11 12:19:06 CDT moms postgres LOG: 00000: execute <unnamed>: insert into moms_patient_change_log (patclog_pat_id, patclog_action, patclog_reason, patclog_date, patclog_user_name, patclog_guid, patclog_id) values ($1, $2, $3, $4, $5, $6, $7) 
2011-05-11 12:19:06 CDT moms postgres DETAIL: parameters: $1 = '17108', $2 = 'Deleted ChemoRegimen ABVD', $3 = NULL, $4 = '2011-05-11 12:19:06.813', $5 = 'daver', $6 = 'BFAA9D91-7A4E-835E-7A57-B72B2A79A4F1', $7 = '520' 

[감사 로그 레코드가 삽입된다] 그게이다. 감사 로그 삽입 트랜잭션은 완료되지 않습니다. 화학 요법을 삭제하기위한 거래 역시 결코 커밋되지 않습니다. 나는 그것을 감사하지 않을 때 ChemoRegimen의 CRUD를 잘 수행 할 수 있습니다. ChemoRegimen 엔티티의 조각은 다음과 같습니다 : 어떤 도움을 크게 감상 할 수

public class MomsInterceptor extends EmptyInterceptor 
{ 
    private static Logger logger = Logger.getLogger(MomsInterceptor.class.getName()); 
    private static Configuration configuration; 
    private static SessionFactory sessionFactory; 

//Create the initial SessionFactory from the default configuration files 
    static 
    { 
    initSessionFactory(); 
    } 

    public static void initSessionFactory() 
    { 
    try 
    { 
     configuration = new Configuration().configure(); 
     sessionFactory = configuration.buildSessionFactory(); 
    } 
    catch (Throwable ex) 
    { 
     // We have to catch Throwable, otherwise we will miss 
     // NoClassDefFoundError and other subclasses of Error 
     logger.severe("Building SessionFactory failed - " + ex.getMessage()); 
     System.err.println("Building SessionFactory failed - " + ex.getMessage()); 
     throw new ExceptionInInitializerError(ex.getMessage()); 
    } 
    } 

    private Set<Auditable> inserts = new HashSet<Auditable>(); 
    private Set<UpdatedEntity> updates = new HashSet<UpdatedEntity>(); 
    private Set<Auditable> deletes = new HashSet<Auditable>(); 
    private boolean audit; 

    public MomsInterceptor(boolean audit) 
    { 
    super(); 
    this.audit = audit; 
    } 

    private class UpdatedEntity 
    { 
    private Auditable auditable; 
    private String[] propertyNames; 
    private Object[] currentState; 
    private Object[] previousState; 
    private Type[] types; 

    public UpdatedEntity(Auditable auditable, String[] propertyNames, Type[] types, Object[] currentState, Object[] previousState) 
    { 
     super(); 
     this.auditable = auditable; 
     this.propertyNames = propertyNames; 
     this.currentState = currentState; 
     this.previousState = previousState; 
     this.types = types; 
    } 

    public Auditable getAuditable() 
    { 
     return auditable; 
    } 

    public String[] getPropertyNames() 
    { 
     return propertyNames; 
    } 

    public Object[] getCurrentState() 
    { 
     return currentState; 
    } 

    public Object[] getPreviousState() 
    { 
     return previousState; 
    } 

    public Type[] getTypes() 
    { 
     return types; 
    } 

    /** 
    * Return the previous value of the property name prop or null if the property name is not found. 
    * @param prop 
    * @return 
    */ 
    public Object getPrevious(String prop) 
    { 
     int i = 0; 
     for (String name : propertyNames) 
     { 
     if (prop.equals(name)) 
      return previousState[i]; 
     i++; 
     } 

     return null; 
    } 
    } 

    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException 
    { 
    boolean modified = false; 
    if (entity instanceof MutableEntity) // Update create info. 
    { 
     MutableEntity me = (MutableEntity)entity; 
     int i = findPropertyNameIndex("createUser", propertyNames); 
     if (i >= 0) 
     state[i] = SessionController.userName; 
     i = findPropertyNameIndex("modifyUser", propertyNames); 
     if (i >= 0) 
     state[i] = SessionController.userName; 
     modified = true; 

     if (audit && entity instanceof Auditable) 
     inserts.add((Auditable)entity); 
    } 

    return modified; 
    } 

    private int findPropertyNameIndex(String name, String[] propertyNames) 
    { 
    int i = -1; 
    if (propertyNames.length == 0) 
     return i; 

    for (String p : propertyNames) 
    { 
     i++; 
     if (p.equals(name)) 
     return i; 
    } 

    return -1; 
    } 

    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) 
     throws CallbackException 
    { 
    boolean modified = false; 

    if (entity instanceof MutableEntity) // Update modify info. 
    { 
     MutableEntity me = (MutableEntity)entity; 
     int i = findPropertyNameIndex("modifyUser", propertyNames); 
     if (i >= 0) 
     currentState[i] = SessionController.userName; 
     i = findPropertyNameIndex("modifyDate", propertyNames); 
     if (i >= 0) 
     currentState[i] = new Date(); 
     modified = true; 

     if (audit && entity instanceof Auditable) 
     updates.add(new UpdatedEntity((Auditable)entity, propertyNames, types, currentState, previousState)); 
    } 

    return modified; 
    } 

    @Override 
    public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) 
    { 
    if (audit && entity instanceof Auditable) 
     deletes.add((Auditable)entity); 
    } 

    @Override 
    public void postFlush(Iterator iterator) throws CallbackException 
    { 
    if (inserts.isEmpty() && deletes.isEmpty() && updates.isEmpty()) 
     return; 

    Session session = sessionFactory.openSession(); 
    session.setFlushMode(FlushMode.COMMIT); 
    session.beginTransaction(); 

    try 
    { 
     String action = null; 
     for (Auditable entity : inserts) 
     { 
     action = "Created " + entity.getClass().getSimpleName() + " " + entity.toString(); 
     session.save(new PatientChangeLog(entity.getPatient(), action, entity.getReason(), SessionController.userName)); 
     } 
     for (Auditable entity : deletes) 
     { 
     action = "Deleted " + entity.getClass().getSimpleName() + " " + entity.toString(); 
     session.save(new PatientChangeLog(entity.getPatient(), action, entity.getReason(), SessionController.userName)); 
     } 
     for (UpdatedEntity entity : updates) 
     { 
     Auditable a = entity.getAuditable(); 
     StringBuffer actionBuf = new StringBuffer("Updated " + a.getClass().getSimpleName() + " " + a.toString() + ": changed "); 
     int count = 0; 
     for (int i = 0; i < entity.getPropertyNames().length; i++) 
     { 
      String prop = entity.getPropertyNames()[i]; 
      Type type = entity.getTypes()[i]; 
      Object curValue = entity.getCurrentState()[i]; 
      Object prevValue = entity.getPreviousState()[i]; 

      //Don't consider the id field or the metadata fields. 
      if (prop.equals("id") || prop.equals("createUser") || prop.equals("createDate") || prop.equals("modifyUser") 
       || prop.equals("modifyDate") || prop.equals("guid")) 
      continue; 

      if (prevValue == null) 
      prevValue = new String(""); 
      if (curValue == null) 
      curValue = new String(""); 
      if (!prevValue.equals(curValue)) 
      { 
      if (count > 0) 
       actionBuf.append(" and "); 
      actionBuf.append(prop).append(" from '").append(prevValue).append("' to '").append(curValue).append("'"); 
      count++; 
      } 
     } 

     Patient p = (Patient)entity.getPrevious("patient"); //In case the patient is changed, tie it to the previous patient. 
     session.save(new PatientChangeLog(p, actionBuf.toString(), a.getReason(), SessionController.userName)); 
     } 

     session.getTransaction().commit(); 
    } 
    catch (HibernateException e) 
    { 
     try 
     { 
     session.getTransaction().rollback(); 
     } 
     catch (Exception hex) 
     { 
     throw new RuntimeException(hex); 
     } 
     throw new RuntimeException(e); 
    } 
    finally 
    { 
     inserts.clear(); 
     updates.clear(); 
     deletes.clear(); 
     session.close(); 
    } 
    } 
} 

:

public class ChemoRegimen extends MOMSEntity implements Auditable 
{ 
    public static final String UNSCHEDULED = "UNSCHEDULED"; 

    private Date date = new Date(); 
    private Patient patient; 
    private WorkingProtocol protocol; 
    private Physician approvingPhysician; 
    private boolean canChangeCycles; 
    private List<ChemoEncounter> chemoEncounters = new ArrayList<ChemoEncounter>(); 
    private boolean complete; 
    private Icdm icdm;<BR> 
    ...<BR> 
} 

이 내 인터셉터입니다.

답변

0

감사 트랜잭션과 Chemo 트랜잭션 사이에 데이터베이스에 교착 상태가 있다고 생각합니다.

1

트랜잭션 간의 교착 상태처럼 보입니다. 감사 트랜잭션은 기본 트랜잭션에 의해 잠긴 리소스를 기다리지 만 인터셉터 실행이 차단되어 커밋 할 수 없습니다.

아마도 Interceptor의 메커니즘이 허용하지 않는 개념적으로 동일한 트랜잭션에서 감사 작업을 실행하는 것이 더 깨끗합니다. 대신 events을 사용해 볼 수 있습니다. 최소한 Envers는 감사 동작을 위해 Envers를 사용합니다.

+0

감사합니다 axtavt 및 @SteveHall. 나는 최대 절전 모드 이벤트를 살펴볼 것이다. – David

+0

axtavt, Envers를 사용하지 않고 감사 로깅을 구현하기 위해 이벤트를 사용하는 데 필요한 모든 설명서를 알고 있습니까? Envers는 주석을 사용하지 않기 때문에 Hibernate와 관련된 주요 변경 사항을 요구합니다. 이런 문서를 찾을 수 없었습니다. – David

2

Envers 대신 Hibernate 이벤트를 사용하기에 적합한 문서를 찾을 수 없으므로 MyInterceptor.postFlush()에서 MyInterceptor.afterTransactionCompletion()으로 코드를 이동하기로 결정했습니다. 이렇게하면 감사 로그 레코드에 대한 새 세션/트랜잭션을 열기 전에 현재 트랜잭션이 커밋되었습니다. 여기까지와 주셔서 감사합니다.

관련 문제