Hibernate 에러 공유 1

2008-03-24 12:35:49,674 WARN [org.hibernate.util.JDBCExceptionReporter] – <SQL Error: 0, SQLState: null>
2008-03-24 12:35:49,674 ERROR [org.hibernate.util.JDBCExceptionReporter] – <Batch entry 0 insert into Material (cdate, itemcnt, itemtypecnt, month, purprice, suppid, udate, materialid) values (2008-03-24 12:35:49.659000 +00:00:00, 0, 0, 200802, 0.0, 1, 2008-03-24 12:35:49.659000 +00:00:00, 89) was aborted.  Call getNextException to see the cause.>
2008-03-24 12:35:49,674 WARN [org.hibernate.util.JDBCExceptionReporter] – <SQL Error: 0, SQLState: 23505>
2008-03-24 12:35:49,674 ERROR [org.hibernate.util.JDBCExceptionReporter] – <ERROR: duplicate key violates unique constraint “=========”>
2008-03-24 12:35:49,674 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] – <Could not synchronize database state with session>
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
    at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:41)
    at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:969)
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1562)
    at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
   
    at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:374)
    at org.springframework.orm.hibernate3.HibernateTemplate.executeFind(HibernateTemplate.java:343)
   
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)

Caused by: java.sql.BatchUpdateException: Batch entry 0 insert into ====  Call getNextException to see the cause.
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2534)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1328)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:352)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2596)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)

이것 때문에 이제 퇴근합니다. 더 늦게가면 운동 할 때 너무 추워서;; 삽질은 한 번으로 끝내자꾸나!!

위와 비슷한 에러를 만나시면, save()를 호출하기 전에 flushAndClear()를 호출해보세요.

외국인들을 위해 영어로도 한 마디..

If you meet this kind errors, just try sychnonize with DB(flushAndClear() or flush())before write(save(), saveOrUpdate()) any data to DB.

잘못 된 openSession() 사용 예제ㅋ

이전 글에서 DAO 구현을 다음과 같이 했었습니다.

public class MemberDaoImpleWIthSpringTransaction implements MemberDao{

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void add(Member member) {
        Session session = sessionFactory.getCurrentSession();
        session.save(member);
    }
}

여기서 빨간 색 부분은 찬욱군이 알려줬기 때문이고 원래는 아래처럼 코딩했었습니다.

    public void add(Member member) {
        Session session = sessionFactory.openSession(); //(1)
        session.save(member);
        session.flush(); //(2)
        session.close(); //(3)
    }

위에 표시한 빨간 부분이 모두 잘못된 부분이였습니다.

(1) 오픈 세션은 새로운 세션을 만들게 되고 그럼 새로운 트랜잭션에서 save를 실행하게 됩니다. 그런데 지금 저 코드는 새로운 트랜잭션이 아니라 Service Layer에서 사용하던 트랜잭션을 사용해야 합니다. 그러려면 새로운 세션이 아닌 getCurrentSession을 사용하면 기존에 존재하는 트랜잭션을 사용하게 됩니다.

(2) flush()는 무조건 DB에 저장하게 된다고 합니다. 따라서 삭제해야합니다. 지금 이 코드는 트랜잭션 내에 있고 예외가 발생하면 롤백해야 되니까 무조건 DB에 넣어버리는 flush()를 사용하면 안되겠습니다.

(3) getCurrentSession은 자기가 알아서 세션을 닫기 때문에 명시적으로 session을 닫아버리면 안됩니다.(에러가 나더군요.)

찬욱군 베리베리 땡큐 감사!!