관리 메뉴

HAMA 블로그

JDBC 트랜잭션 본문

RDBMS (PostgreSQL)

JDBC 트랜잭션

[하마] 이승현 (wowlsh93@gmail.com) 2015. 7. 30. 12:23

JDBC 기본 트랜잭션 


JDBC API의 Connection 객체는 commit() 메소드와 rollback() 메소드를 제공한다.

기본적으로 Connection 객체에 setAutoCommit 이란 메소드가 있는데 기본값이 true 로 설정이 되어 있다. 

하나의 쿼리당 자동시작~자동커밋이 일어난다는 이야기이다.

그러나  여러 개의 쿼리 문장이 하나의 작업으로 수행되어야 할경우에  각각의 문장이  자동으로 작동되지 못하게 해야한다.

오토커밋이 자동으로 작동되지 못하게 하려면 setAutoCommit(false); 로 지정해야 한다.



자 그럼 begin() 은 어딨느냐?? 


AutoCommit = true 일경우



암시적으로 각각의 액션시 (각각 SQL 문에서)  자동으로 BEGIN()



AutoCommit = false  일경우



이건 좀 희안하다. setAutoCommit(false) 를 호출하여 오토커밋코드를 꺼넣으면 시스템은 이 호출과 동시에 BEGIN 요청을 하게


된다. 이후의 commit() 과 rollback() 호출은 해당 SQL 을 호출한 뒤에 다시 BEGIN() 을 요청하게된다. 




그 밖에 setAutoCommit 을 통해 모드를 바꾸면  동시에 commit() 1회 발생한다.






JDBC Savepoint  

번역: http://www.tutorialspoint.com/jdbc/jdbc-transactions.htm


새로운 JDBC 3.0 Savepoint interface 는 추가적인 트랜잭션기능을 제공하는데 . Oracle's PL/SQL 같은 많은 현대 DBMS 에서는 그들의 환경내에 savepoints 를 지원하고있다.  당신이 세이프포인트를 세팅할때 트랜잭션안에 논리적 롤백 포인트를 정의할수있다.

만약 에러가  세이프포인트뒤에 발생하면 , 모든 변경사항 또는  세이브포인트 후에 만들어진 변화를 undo 를 하기위해  롤백메소드를  사용할수있다. 

Connection 객체는 2가지 새로운 메소드로 세이브포인트를 요리할수있도록 도와준다.

  • setSavepoint(String savepointName):  새로운 세이브포인트를 정의하고 그 객체를  리턴받는다.

  • releaseSavepoint(Savepoint savepointName): 세이브포인트 삭제. 

 rollback (String savepointName) 는  특정 세이브포인트로 작업을 롤백한다.


다음 예를 통해 살펴보자.

try{ conn.setAutoCommit(false); Statement stmt = conn.createStatement(); // Savepoint 설정 Savepoint savepoint1 = conn.setSavepoint("Savepoint1"); String SQL = "INSERT INTO Employees " + "VALUES (106, 20, 'Rita', 'Tez')"; stmt.executeUpdate(SQL); String SQL = "INSERTED IN Employees " + "VALUES (107, 22, 'Sita', 'Tez')"; stmt.executeUpdate(SQL); conn.commit(); }catch(SQLException se){ conn.rollback(savepoint1); }


문제가 생기면 savepoint1 까지 롤백된다. insert 문은 작동안하겠지


좀더 구체적인 예를 살펴봅시다.

//STEP 1. 관련 패키지 임포트 import java.sql.*; public class JDBCExample { static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; Statement stmt = null; try{ //STEP 2: JDBC 드라이버 등록 Class.forName("com.mysql.jdbc.Driver"); //STEP 3: connection 맺고 System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //STEP 4: 오토 커밋 않하게함 conn.setAutoCommit(false); //STEP 5: statment 생성 System.out.println("Creating statement..."); stmt = conn.createStatement(); //STEP 6: 모든 데이터 가져오기 String sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); System.out.println("List result set for reference...."); printRs(rs); // STEP 7: 세이브 포인트1 설정 Savepoint savepoint1 = conn.setSavepoint("ROWS_DELETED_1");  

// STEP 8: ID = 110 삭제

System.out.println("Deleting row...."); String SQL = "DELETE FROM Employees WHERE ID = 110"; stmt.executeUpdate(SQL);  

// 엇.. 잘못된 놈을 지웠네.. //STEP 8: Rollback the changes afetr save point 2. conn.rollback(savepoint1); // STEP 9: 세이브 포인트 2 설정 Savepoint savepoint2 = conn.setSavepoint("ROWS_DELETED_2");  

System.out.println("Deleting row...."); SQL = "DELETE FROM Employees WHERE ID = 95"; stmt.executeUpdate(SQL); //STEP 10: Now list all the available records. sql = "SELECT id, first, last, age FROM Employees"; rs = stmt.executeQuery(sql); System.out.println("List result set for reference...."); printRs(rs); //STEP 10: Clean-up environment rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); // If there is an error then rollback the changes. System.out.println("Rolling back data here...."); try{ if(conn!=null) conn.rollback(); }catch(SQLException se2){ se2.printStackTrace(); }//end try }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main public static void printRs(ResultSet rs) throws SQLException{ //Ensure we start with first row rs.beforeFirst(); while(rs.next()){ //Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); //Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); } System.out.println(); }//end printRs() }//end JDBCExample

다음처럼 컴파일하고

C:\>javac JDBCExample.java
C:\>

JDBCExample 실행하면 다음과 같이 나오게된다. 

C:\>java JDBCExample
Connecting to database...
Creating statement...
List result set for reference....
ID: 95, Age: 20, First: Sima, Last: Chug
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
ID: 110, Age: 20, First: Sima, Last: Chug

Deleting row....
Deleting row....
List result set for reference....
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
ID: 110, Age: 20, First: Sima, Last: Chug

Goodbye!
C:\>


ORACLE  Savepoint
펌 : http://reiphiel.tistory.com/entry/jdbc-transaction-savepoints

  

SQL예(오라클)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INSERT INTO TEST_USER (NAME) VALUES ('JOHN');
 
SAVEPOINT MARK;
INSERT INTO TEST_USER (NAME) VALUES ('MARK');
 
SAVEPOINT JACK;
INSERT INTO TEST_USER (NAME) VALUES ('JACK');
 
SAVEPOINT PAUL;
INSERT INTO TEST_USER (NAME) VALUES ('PAUL');
 
ROLLBACK TO JACK;
 
INSERT INTO TEST_USER (NAME) VALUES ('JANE');
 
COMMIT;


실행 결과




SQL문은 실행한 결과는 위와 같은데 SAVEPOINT로 특정 세이브포인트까지 롤백을 하게되면 롤백실행한 


부분부터지정한 세이브 포인트까지 롤백 되는 것을 알수있다. 



구조적으로 나중에 지정한 세이브포인트는 직전 세이브 포인트에 종속적이라고 보면 되겠다. 


중첩된 트랜잭션이라고 보면 되겠다. 그리고 지정한 세이브포인트 이전과 롤백을 실행한 이후의 SQL에는 


영향을 미치지 않았다는 것을 알 수 있다.


Comments