복붙노트

[SPRING] 최대 절전 모드에서 예외를 throw하지 않는 DB 제약 위반

SPRING

최대 절전 모드에서 예외를 throw하지 않는 DB 제약 위반

다음 코드가 있습니다.

try {
    userDAO1.save(userRecord);
    userDAO2.save(userRecord);
}
catch(DataIntegrityViolationException e) {
    throw new ApplicationException("Contraint violated")
}

userDAO1.save (userRecord)는 무결성 제약 조건을 위반하므로 전체 코드가 실행 된 후 userDAO1이 참조하는 테이블에 아무 것도 기록되지 않습니다.

그러나 userDAO1.save () 문은 오류 / 예외를 throw하지 않으므로 userDAO2.save ()도 실행됩니다.

그러나 DataIntegrityViolationException이 잡히고 스택 추적이 null입니다.

UserDAO1.save ()가 제약 조건을 위반하면, DataIntegrityViolationException이 어디에서 던져 졌는지 확인하고 userDAO2.save ()가 실행되지 않도록하려면 어떻게해야합니까?

이 코드 주위에 @Transactional 주석을 추가하려고 시도했지만 그 중 하나도 작동하지 않았습니다.

스택 추적 :

org.springframework.dao.DataIntegrityViolationException: ORA-00001: unique constraint (UNIQUE_EMAIL) violated
; SQL [n/a]; constraint [UNIQUE_EMAIL]; nested exception is org.hibernate.exception.ConstraintViolationException: ORA-00001: unique constraint (UNIQUE_EMAIL) violated

    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:516)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy76.updateUser(Unknown Source)
    at com.osiris.UserReg.UpdateUserCommand.execute(UpdateUserCommand.java:63)

내가 게시 한 코드는 @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)으로 주석 된 UpdateUserCommand에 있습니다.

해결법

  1. ==============================

    1.좋아, 이건 좀 까다 롭긴하지만 최선을 다할거야. Hibernate는 @Transactional으로 주석 된 메소드가 종료 될 때만 트랜잭션을 커밋 할 것이다. 따라서 DataIntegrityViolationException은 해당 메서드가 반환 된 후에 만 ​​catch 할 수 있습니다. 당신이 UserDAO2.save ()를 호출하지 않을 수있는 방법은 없다. 왜냐하면 그것이 위반이 발생했다는 것을 탐지 할 수 없기 때문이다. 아래 예제를 제공합니다.

    좋아, 이건 좀 까다 롭긴하지만 최선을 다할거야. Hibernate는 @Transactional으로 주석 된 메소드가 종료 될 때만 트랜잭션을 커밋 할 것이다. 따라서 DataIntegrityViolationException은 해당 메서드가 반환 된 후에 만 ​​catch 할 수 있습니다. 당신이 UserDAO2.save ()를 호출하지 않을 수있는 방법은 없다. 왜냐하면 그것이 위반이 발생했다는 것을 탐지 할 수 없기 때문이다. 아래 예제를 제공합니다.

    @Service
    /*These variable names are used for clarity's sake, I don't actually use these names myself*/
    public UserServiceImpl implements UserService{
        @Autowired
        private HibernateUserDAO1 userDao1;
        @Autowired
        private HibernateUserDAO2 userDao2
    
        @Transactional
        /*Put your try catch block around where this method is called*/
        public void saveUserDao1(User user){
             userDao1.saveOrUpdate(user);
        }
    
        @Transactional
        /*Only call this if saveUserDao1 succeeds*/
        public void saveUserDao2(User user){
              userDao2.saveOrUpdate(user)
        }
    }
    

    그런 다음 당신의 HibernateUserDAO1에서 :

    public void saveOrUpdate(User user){
         currentSession().saveOrUpdate(user);
    }
    

    예외는 서비스 계층 위에서 만 발견 할 수 있습니다. 이상적으로하고 싶은 일은 두 가지 DAO를 사용하여 개별 저장하고 두 번째 DAO를 수행하기 전에 먼저 성공했는지 확인하는 것입니다.

    편집 : 또한 Hibernate는 @Transactional로 주석 된 private 메소드를 선택하지 않을 것이라는 점에 유의해야한다. 왜냐하면 Hibernate는 클래스가 구현하는 인터페이스로부터 Proxy 객체를 생성하기 때문이다. 인터페이스 정의 없음 = 프록시 객체 없음 = 최대 절전 모드 세션 없음. 따라서 @Transactional 주석이 달린 개인 메소드를 호출 할 수 없습니다. SessionFactory를 추상적 인 수퍼 클래스에 객체로 만들고 DAO의 두 인스턴스를 상속 받도록하려고합니다. 더 나은 옵션은 각각 다른 데이터베이스를 가리키는 2 개의 트랜잭션 관리자를 사용하고 어떤 데이터베이스가 저장되는지 지정하는 것입니다. 그렇게하면 DAO를 1 개만 사용할 수 있고 저장을 수행하는 데 필요한 세션 팩터 리를 사용할 수 있습니다.

  2. ==============================

    2.userDAO1.save () 문이 실행되는 동안 DataIntegrityViolationException이 발생하지 않았다고 생각하는 이유가 무엇입니까? 또한, userDAO2.save ()가 실행되었다고 생각하는 이유는 무엇입니까?

    userDAO1.save () 문이 실행되는 동안 DataIntegrityViolationException이 발생하지 않았다고 생각하는 이유가 무엇입니까? 또한, userDAO2.save ()가 실행되었다고 생각하는 이유는 무엇입니까?

    Eclipse Eclipse와 같은 IDE 디버그 콘솔에서 코드 실행 진행을 관찰 한 결과 위의 의견이 나온 경우 해석이 잘못되었을 수 있습니다.

    아래에있는 것과 같은 디버그 문을 펀치 인하 고 코드를 실행하여 결과를 관찰하십시오. 이것은 장애의 근본 원인을 찾아내는 데 도움이 될 수 있습니다.

    try {
        userDAO1.save(userRecord);
        System.out.println("-- After userDAO1.save(userRecord) --");
        userDAO2.save(userRecord);
        System.out.println("-- After userDAO2.save(userRecord) --");
    } catch(DataIntegrityViolationException e) {
        e.printStackTrace();
        throw new ApplicationException("Contraint violated")
    }
    
  3. from https://stackoverflow.com/questions/21822663/db-constraint-violation-not-throwing-exception-in-hibernate by cc-by-sa and MIT license