2016-11-24 1 views
4

Java 8로 트랜잭션을 작성하고 있습니다. 먼저, 제 코드는 이와 같습니다. 내가 트랜잭션 실패시 롤백해야하기 때문에Java 8에서 명령문 실행 실패를 롤백하는 가장 좋은 방법은 무엇입니까?

try (Connection conn = DAOUtil.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(addSubscriptionSql)) { 
    conn.setAutoCommit(false); 
    //do work 
    conn.commit(); 
} catch (SQLException e) { 
    e.printStackTrace(); //handle error 
} 

는하지만,이 같은 코드를 변경했다. 2 개의 try 블록을 주목하십시오.

try (Connection conn = DAOUtil.getConnection()) { 
    try (PreparedStatement ps = conn.prepareStatement(addSubscriptionSql)) { 
     conn.setAutoCommit(false); 
     //do work 
     conn.commit(); 
    } catch (SQLException e) { 
     conn.rollback(); 
     e.printStackTrace(); //handle error 
    } 
} catch (SQLException e) { 
    e.printStackTrace(); //handle error 
} 

제 질문은이 방법을 사용하는 것이 더 나은가요? 단일 try 블록으로이 작업을 수행 할 수 있습니까?

답변

6

당신이 항상 rollback()를 호출하지만, commit()의 성공적인 완료 후, 롤백은 어떤 조합이 될 것

try(Connection conn = DAOUtil.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(addSubscriptionSql); 
    AutoCloseable finish = conn::rollback) { 

    conn.setAutoCommit(false); 
    //do work 
    conn.commit(); 
} 

사용할 수 있습니다 ...

AutoCloseable은이 광범위한 예외 유형을 처리해야 할 Exception을 던집니다. 그것은뿐만 아니라 다른 경우에 유용 할 수있는 사용자 정의 유형 고정 할 수 있습니다

interface SQLCloseable extends AutoCloseable { 
    @Override public void close() throws SQLException; 
} 

...

try(Connection conn = DAOUtil.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(addSubscriptionSql); 
    SQLCloseable finish = conn::rollback) { 

    conn.setAutoCommit(false); 
    //do work 
    conn.commit(); 
} 

지금, 예외 유형 SQLException의 처리가 적용됩니다. 그 지표로 당신이 마지막에 자동 위탁 상태를 재설정하면

boolean[] success = { false }; 
try(Connection conn = DAOUtil.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(addSubscriptionSql); 
    SQLCloseable finish =() -> { if(!success[0]) conn.rollback(); }) { 

    conn.setAutoCommit(false); 
    //do work 
    conn.commit(); 
    success[0] = true; 
} 

, 당신은 사용할 수 있습니다 : 당신이 무조건 호출되는 rollback()의 아이디어를 좋아하지 않는 경우에

이 솔루션은 덜 우아하게 롤백의 필요성을 위해 :

try(Connection conn = DAOUtil.getConnection(); 
    PreparedStatement ps = conn.prepareStatement(addSubscriptionSql); 
    SQLCloseable finish =() -> { if(!conn.getAutoCommit()) conn.rollback(); }) { 

    conn.setAutoCommit(false); 
    //do work 
    conn.commit(); 
    conn.setAutoCommit(true); 
} 
+0

영리한! 공유해 주셔서 감사합니다. –

+1

그것은 똑똑한 해결책입니다. +1을 위해서 그렇지만, 코드베이스에서 얼마나 많은 사람들이 이것을 이해할 수 있는지 이해할 수 있을지 궁금합니다. –

5

하나의 try 블록으로이 작업을 수행 할 수 있습니까?

없음

, 당신의 conn 목적은 당신의 시도 --자원의 catch 블록에서 사용할 수 없습니다 때문입니다. PreparedStatement을 실행하는 동안 예외를 catch하고 명시 적으로 conn.rollback()을 수행하려는 경우 conn 개체를 만드는 try-with-resources의 try 내에서 롤백해야합니다 (예 : PreparedStatement에 대해 두 번째로 중첩 된 try 블록 사용). 요구). 이 commit()의 마지막을 성공적으로 완료 한 후 그것의 상태를 재설정으로

관련 문제