본문 바로가기
ICIA 수업일지

2021.07.13 수업일지

by 주성씨 2021. 7. 17.
package ex1;

// 이런 클래스는 데이터 bean, DTO(data transfer object) 라고 한다.
// 데이터 전송 오브젝트
// 데이터를 저장하는 목적으로 만든 클래스
public class Member { 
	
	//lombok이라는 유틸리티를 이용하면 getter, setter을 자동으로 생성해준다.

	private String id;
	private String pw;
	private String name;
	private int age;
	
	// get, set 메서드를 만들기 때문에 생성자는 꼭 안만들어도 된다.
//	public Member(String id, String pw, String name, int age) {
//		this.id=id;
//		this.pw=pw;
//		this.name=name;
//		this.age=age;
//	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPw() {
		return pw;
	}
	public void setPw(String pw) {
		this.pw = pw;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "아이디 = "+id+", 비밀번호 = "+pw+", 이름 = "+name+", 나이 = "+age;
	}
	
}

ㄴ 데이터를 전송하기 위해서 데이터를 저장하는 클래스
ㄴ 이런 DTO에서는 생성자를 만들지 않는다. 만들더라도 오류가 있을 가능성이 있다.

 

	// login 업무 생성
	// 로그인에 성공했으면 회원정보를 가지고 가겠다.
	public Member login(String id, String pw) {
		try {
			stmt = con.createStatement();
			String sql = "SELECT * FROM MEMBER WHERE ID='"+id+"' AND PW='"+pw+"'";
			rs= stmt.executeQuery(sql);
			Member mb = new Member(); //DTO
			if(rs.next()) {
				mb.setId(rs.getNString("ID"));
				mb.setPw(rs.getNString("PW"));
				mb.setName(rs.getNString("NAME"));
				mb.setAge(rs.getInt("AGE"));
				
				return mb;
				
				// 생성자는 get,set 때문에 꼭 안만들어도 된다.
//				return new Member(id,pw,name,age);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

ㄴ 아래와 같이 변경할 수 있다.

			Member mb = null;
			if(rs.next()) {
				mb = new Member();

 

- SQL
- zoodb에 관리자 계정을 insert 해준다.

insert into member values('adim','1111','관리자',15);
UPDATE member SET id = 'admin'
where name = '관리자';
commit;

 

- java
- 아이디가 admin인 경우에 로그인 데이터를 어떻게 가지고 올것인지
- 관리자로 로그인할경우 arraylist에 담아서 리턴하는 코드

	public List<Member> login(String id, String pw) {
		try {
			stmt = con.createStatement();
			String sql = "SELECT * FROM MEMBER WHERE ID='" + id + "' AND PW='" + pw + "'";
			rs = stmt.executeQuery(sql);
			List<Member> mList = new ArrayList<>();
			Member mb = null;
			if (rs.next()) {
				if (rs.getNString("ID").equals("admin")) { // 관리자
					sql = "SELECT * FROM MEMBER";
					rs = stmt.executeQuery(sql);
					while (rs.next()) {
						mb = new Member();
						mb.setId(rs.getNString("ID"));
						mb.setPw(rs.getNString("PW"));
						mb.setName(rs.getNString("NAME"));
						mb.setAge(rs.getInt("AGE"));
						mList.add(mb);
					}
					return mList; //모든 회원의 정보를 반환
				} else { // 일반
					mb = new Member();
					mb.setId(rs.getNString("ID"));
					mb.setPw(rs.getNString("PW"));
					mb.setName(rs.getNString("NAME"));
					mb.setAge(rs.getInt("AGE"));
					mList.add(mb);
					return mList; //본인 정보만 반환
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

ㄴ bean은 미리 만들지 말자 데이터가 필요할때만 가지고 올 수 있게 하자. 만약 미리 만든다면 하나의 dto에 정보를 다 넣기 때문에 데이터 중복이 발생할 수 있다. 온전한 데이터가 나오지 않는다.

 

- LoginMain의 메인 메서드를 수정한다.

public class LoginMain {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.print("아이디 입력 : ");
		String id = sc.next();
		System.out.print("패스워드 입력 : ");
		String pw = sc.next();

		LoginBL lb = new LoginBL();
		lb.connect();
		List<Member> mList = lb.login(id, pw);
		for(int i=0; i<mList.size(); i++) {
			System.out.println(mList.get(i).toString()); // 하나씩 꺼내겠다. toString 생략 가능
		}
		lb.close();
		
//		if (mb == null) {
//			System.out.println("로그인 실패");
//		} else {
//			mb.toString();
//		}

	}

}

ㄴ 실패할 경우도 추가해준다.

		LoginBL lb = new LoginBL();
		lb.connect();
		List<Member> mList = lb.login(id, pw);
		if (mList == null) {
			System.out.println("로그인 실패");
		}
		for (int i = 0; i < mList.size(); i++) {
			System.out.println(mList.get(i)); // 하나씩 꺼내겠다. toString 생략 가능
		}
		lb.close();

 

- 파라미터가 많은 경우의 sql문을 어떻게 개선할 수 있을까?
- 파싱 작업을 다시 하지 않는 PrepareStatement 인터페이스

- LoginBL을 PrepareStatement 인터페이스를 적용하여 개선해보자.

public class LoginBL {

	Connection con;
	PreparedStatement stmt = null; //변경
	ResultSet rs = null;

ㄴ Statement 를 PreparedStatement로 변경

	public List<Member> login(String id, String pw) {
		try {
			String sql = "SELECT * FROM MEMBER WHERE ID=? AND PW=?"; //위로, 변경
			stmt = con.prepareStatement(sql); // 파싱(분석)1번, 구문분석
			stmt.setNString(1, id); // 첫번째 문자열 id
			stmt.setNString(2, pw); // 두번째 문자열 pw
			rs = stmt.executeQuery(); // 파싱을 앞서 했기 때문에 sql 생략

ㄴ prepareStatement 에 맞게 변경

			List<Member> mList = new ArrayList<>();
			Member mb = null; // bean은 미리 만들지 말자 데이터가 필요할때만 가지고 올 수 있게 하자.
			if (rs.next()) {
				if (rs.getNString("ID").equals("admin")) { // 관리자
					sql = "SELECT * FROM MEMBER";
					stmt=con.prepareStatement(sql); //파싱(분석) 1번
					rs = stmt.executeQuery(); //앞선 파싱때문에 파싱 생략

 

- 새로운 프로젝트 생성

+ 빌드 패스에  ojdbc6.jar 드라이버 추가
+ ex1 패키지에 PreparedStatementTest 클래스 생성
+ 드라이버 연결, db 연결, db 연결 해제는 복붙해도 좋지만 각 필드값, ip, db id pw 등 차이는 확인하도록 한다.

 

package ex1;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PreparedStatementTest {
	// 필드
	// 여러개의 메서드에서 편하게 사용할 수 있어서 필드에 올려두는게 좋다.
	Connection con;
	ResultSet rs;
	PreparedStatement pstmt;
	// 드라이버 로딩
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
			System.out.println("드라이버 로딩 실패");
			e.printStackTrace();
		}
	}
	// 연결
	public void connect() {
		try {
			// 지역변수에 있는 Connection은 지워주도록 한다.
			con = DriverManager.getConnection
			// @ 이하는 실제 DB의 IP를 적어야한다.
			// 복붙해도 좋지만 ip, db id pw는 반드시 확인하도록 한다.
			("jdbc:oracle:thin:@localhost:1521:xe", "icia", "1111");
			// DB id, pw
			System.out.println("DB 접속 성공");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}
	}
	// 연결 해제
	public void close() {
		try {
			if(rs!=null) rs.close();
			if(pstmt!=null) pstmt.close();
			if(con!=null) con.close();
			System.out.println("close 성공");
		} catch (SQLException e) {
			System.out.println("close 실패");
			e.printStackTrace();
		}
	}

 

- 데이터 삽입 메서드 만들기

	public void insert(String id, String pw, String name, int age) {
		String sql = "INSERT INTO MEMBER VALUES(?,?,?,?)"; //보안성 높임
		try {
			pstmt = con.prepareStatement(sql); // 파싱
			pstmt.setNString(1, id);
			pstmt.setNString(2, pw);
			pstmt.setNString(3, name);
			pstmt.setInt(4, age);
			
			int cnt = pstmt.executeUpdate(); //sql문 실행
			if(cnt>0) {
				System.out.println("insert 성공");
			} else {
				System.out.println("insert 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("insert 예외");
			e.printStackTrace();
		} //파싱
	} // insert end

ㄴ 이전과 다르게 prepareStatement를 이용해서 만들어보자.

 

- 데이터 검색 메서드 만들기

	// 데이터 검색
	public void select() {
		try {
			String sql = "SELECT * FROM MEMBER";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			while(rs.next()) {
			System.out.println("아이디 : "+rs.getNString("id")+" 패스워드 : "+rs.getNString("pw")
			+" 이름 : "+rs.getNString("name")+" 나이 : "+rs.getNString("age"));
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("select 예외 발생");
			e.printStackTrace();
		}
	} // select end

ㄴ 이전과 다르게 prepareStatement를 이용해서 만들어보자.

 

- ArrayList를 이용해서 데이터를 축적하여 검색 메서드를 변경하고 검색 후 출력까지 해보자.

package ex1;

import java.util.List;

public class PstmtMain {

	public static void main(String[] args) {
		PreparedStatementTest pt = new PreparedStatementTest();
		pt.connect();
//		pt.insert("fff","1111","에프",20); // 파라미터 값 넣어보기
		
		List<Member> mList = pt.select();
		for(Member mb:mList) {
			System.out.println(mb);
		}
		pt.close();
	}

}

 

	// 데이터 검색
	public List<Member> select() {
		try {
			String sql = "SELECT * FROM MEMBER";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			List<Member> mList = new ArrayList<>();
			Member mb = null;
			while(rs.next()) {
			mb = new Member(); //인스턴스 생성
			mb.setId(rs.getNString("ID"));
			mb.setPw(rs.getNString("PW"));
			mb.setName(rs.getNString("NAME"));
			mb.setAge(rs.getInt("Age"));
			mList.add(mb); // 데이터 축적
			}
			return mList;
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("select 예외 발생");
			e.printStackTrace();
		}
		return null;
	} // select end
	@Override
	public String toString() {
		return "아이디 = "+id+", 비밀번호 = "+pw+", 이름 = "+name+", 나이 = "+age;
	}

 

- 데이터 수정 메서드

		pt.insert("fff","1111","에프",20); // 파라미터 값 넣어보기
	// 데이터 수정
	public void update(String id, String pw, int age) {
		String sql = "UPDATE MEMBER SET PW=?,AGE=? WHERE ID=?";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setNString(1, pw);
			pstmt.setInt(2, age);
			pstmt.setNString(3, id);
			int cnt = pstmt.executeUpdate();
			if (cnt > 0) {
				System.out.println("update 성공");
			} else {
				System.out.println("update 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("update 예외");
			e.printStackTrace();
		}

	}

 

- 데이터 삭제 메서드

		pt.delete("fff");
	public void delete(String id) {
		String sql = "DELETE FROM MEMBER WHERE ID=?";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setNString(1, id);
			int cnt = pstmt.executeUpdate();
			if(cnt>0) {
				System.out.println("delete 성공");
			} else {
				System.out.println("delete 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("delete 예외");
			e.printStackTrace();
		}
		
	}

 

- SQL
- 이체 트랜젝션

update b계좌 잔고 감소;
update a계좌 잔고 증가;

 

- 둘다 성공하면 commit
- 둘중 하나라도 실패하면 rollback

 

- 작업 취소를 가능하게 하는 트랜잭션

- 트랜잭션은 분리할 수 없는 하나의 논리적인 작업 단위이다.
- 여러개의 DML 문장을 하나의 논리적인 실행 단위로 묶어서 그중 하나라도 실패하면 전체를 취소하는 기능이다. 즉 결제 처리가 안되고 주문 데이터가 삽입되면 전체를 취소 처리해야 한다.
- Connection 객체는 SQL 문장을 실행하면 트랜잭션이 걸리지 않고 작업이 즉시 완성된다. 따라서 여러작업을 트랜잭션으로 묶어주고 싶다면 다음과 같이 설정해주도록 하자.

Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe",
"해당 DB", "DB의 비밀번호");
con.setAutoCommit(false);

- con.setAutoCommit(false); 를 지정하면 해당 Connection 객체를 이용해 실행한 DML문장은 commit() 메서드를 호출하면 작업이 완료되고, rollback()메서드를 호출하면 작업이 취소된다.

 

- SQL
- TRANSACTION TEST

- 이전에 만들었던 드라이버 로딩, 서버 커넥트, 서버 언커넥트는 복사해서 가지고 오도록 하자.

package ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TransactionTest {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs=null;
	
	// 드라이버 로딩
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
			System.out.println("드라이버 로딩 실패");
			e.printStackTrace();
		}
	}

	// 연결
	public void connect() {
		try {
			// 지역변수에 있는 Connection은 지워주도록 한다.
			con = DriverManager.getConnection
			// @ 이하는 실제 DB의 IP를 적어야한다.
			// 복붙해도 좋지만 ip, db id pw는 반드시 확인하도록 한다.
			("jdbc:oracle:thin:@localhost:1521:xe", "zoodb", "1111");
			// DB id, pw
//			con.setAutoCommit(true); //기본값 자동 commit;
			con.setAutoCommit(false); //수동 commit
			System.out.println("DB 접속 성공");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}
	} // connect end

	// 연결 해제
	public void close() {
		try {
			if (rs != null)
				rs.close();
			if (pstmt != null)
				pstmt.close();
			if (con != null)
				con.close();
			System.out.println("close 성공");
		} catch (SQLException e) {
			System.out.println("close 실패");
			e.printStackTrace();
		}
	} // close end
	
	public static void main(String[] args) {

	}

}

 

- main 메서드와 주문 메서드를 만들어 보자.

	public static void main(String[] args) {
		TransactionTest tt = new TransactionTest();
		tt.connect();
		tt.order();
		tt.close();
	}
	private void order() {
		boolean isOrderSuccess = false; // tx성공 : true, 실패 : false
		String sql = "INSERT INTO PAY VALUES('aaa','001',1000)";
		try {
			pstmt = con.prepareStatement(sql); //파싱
			int cnt = pstmt.executeUpdate();
			sql ="INSERT INTO ORDERLIST VALUES('001','TV')";
			pstmt = con.prepareStatement(sql);
			int cnt2 = pstmt.executeUpdate();
			if(cnt>0 && cnt2>0) {
				isOrderSuccess = true;
				System.out.println("tx insert 성공");
			} else {
				isOrderSuccess = false; //생략 가능
				System.out.println("tx insert 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("insert 예외");
			e.printStackTrace();
		} finally {
			if(isOrderSuccess) {
				try {
					con.commit();
					System.out.println("commit 성공");
				} catch (SQLException e) {
					System.out.println("commit 예외");
					e.printStackTrace();
				}
			} else {
				try {
					con.rollback();
					System.out.println("rollback 성공");
				} catch (SQLException e) {
					System.out.println("rollback 예외");
					e.printStackTrace();
				}
			}
			
		}
		
	}

 

- 확인(SQL)

select * from pay;
select * from orderlist;

 

- 만약 pay insert 는 정상적으로 하고 orderlist에서 데이터 하나를 빼먹는다면?

		String sql = "INSERT INTO PAY VALUES('bbb','002',1000)";
		try {
			pstmt = con.prepareStatement(sql); //파싱
			int cnt = pstmt.executeUpdate();
			sql ="INSERT INTO ORDERLIST VALUES('001')";
DB 접속 성공
ORA-00947: not enough values

insert 예외
java.sql.SQLSyntaxErrorException: ORA-00947: not enough values

	at ojdbc6/oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
	at ojdbc6/oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
	at ojdbc6/oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
	at ojdbc6/oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
	at ojdbc6/oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191)
	at ojdbc6/oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523)
	at ojdbc6/oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
	at ojdbc6/oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1010)
	at ojdbc6/oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
	at ojdbc6/oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576)
	at ojdbc6/oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657)
	at ojdbc6/oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
	at ex2.TransactionTest.order(TransactionTest.java:74)
	at ex2.TransactionTest.main(TransactionTest.java:62)
rollback 성공
close 성공

ㄴ 둘 중에 하나라도 실패하게 된다면 rollback이 되어야 한다.

 

- JdbcUtil 라고 명명한 공통 클래스를 생성해보자.

- TransactionTest에 복사해뒀던 드라이버 로딩, 서버 연결, 서버 연결 해제문을 가지고오도록 한다.
- 위와 같은 구문은 공통적으로 사용하기 때문에 공통 클래스를 두어서 어느 작업에서도 이용할 수 있도록 하는게 좋다.

package common;

import java.sql.DriverManager;
import java.sql.SQLException;

public class JdbcUtil {

	// 드라이버 로딩
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
			System.out.println("드라이버 로딩 실패");
			e.printStackTrace();
		}
	}

	// 연결
	public void connect() {
    	Connection con = null; // 지역변수, 지역변수는 초기화 안되니 null을 지정
		try {
			// 지역변수에 있는 Connection은 지워주도록 한다.
			con = DriverManager.getConnection
			// @ 이하는 실제 DB의 IP를 적어야한다.
			// 복붙해도 좋지만 ip, db id pw는 반드시 확인하도록 한다.
			("jdbc:oracle:thin:@localhost:1521:xe", "zoodb", "1111");
			// DB id, pw
//			con.setAutoCommit(true); //기본값 자동 commit;
			con.setAutoCommit(false); // 수동 commit
			System.out.println("DB 접속 성공");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}
	} // connect end

	// 연결 해제
	public void close() {
		try {
			if (rs != null)
				rs.close();
			if (pstmt != null)
				pstmt.close();
			if (con != null)
				con.close();
			System.out.println("close 성공");
		} catch (SQLException e) {
			System.out.println("close 실패");
			e.printStackTrace();
		}
	} // close end

} // class end

- 드라이버 로딩을 제외하고 연결과 연결 해제는 다음과 같이 수정해준다.

	// 연결
	public Connection connect() {
		Connection con = null; // 지역변수, 지역변수는 초기화 안되니 null을 지정
		try {
			con = DriverManager.getConnection
			("jdbc:oracle:thin:@localhost:1521:xe", "zoodb", "1111");
//			con.setAutoCommit(true); //기본값 자동 commit;
			con.setAutoCommit(false); // 수동 commit
			System.out.println("DB 접속 성공");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}
		return con; // 실패 : null 반환, 성공 : null 아닌 값을 반환
	} // connect end
	// 연결 해제
	// close(rs.pstmt,com); 한번에
	// close(rs); close(pstmt); close(con); 각각
	public void close(ResultSet rs, PreparedStatement pstmt, Connection con) {
		try {
			if (rs != null)
				rs.close();
			if (pstmt != null)
				pstmt.close();
			if (con != null)
				con.close();
			System.out.println("close 성공");
		} catch (SQLException e) {
			System.out.println("close 실패");
			e.printStackTrace();
		}
	} // close end

 

- 위와 마찬가지로 공통적으로 이용되는 commit, rollback을 가지고오자.

	// rollback(con);
	private void rollback(Connection con) {
		try {
			con.rollback();
		} catch (SQLException e) {
			System.out.println("rollack 예외");
			e.printStackTrace();
		}
	}

	// commit(con);
	private void commit(Connection con) {
		try {
			con.commit();
		} catch (SQLException e) {
			System.out.println("commit 예외");
			e.printStackTrace();
		}
	}

 

- class JdbcUtil

- connect 메서드의 이름은 가독성을 위해서 getConnection으로 변경해준다.

package common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JdbcUtil {

	// 드라이버 로딩
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
			System.out.println("드라이버 로딩 실패");
			e.printStackTrace();
		}
	}

	// 연결
	public static Connection getConnection() {
		Connection con = null; // 지역변수, 지역변수는 초기화 안되니 null을 지정
		try {
			con = DriverManager.getConnection
			("jdbc:oracle:thin:@localhost:1521:xe", "zoodb", "1111");
//			con.setAutoCommit(true); //기본값 자동 commit;
			con.setAutoCommit(false); // 수동 commit
			System.out.println("DB 접속 성공");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}
		return con; // 실패 : null 반환, 성공 : null 아닌 값을 반환
	} // connect end

	// 연결 해제
	// close(rs.pstmt,com); 한번에
	// close(rs); close(pstmt); close(con); 각각
	public static void close(ResultSet rs, PreparedStatement pstmt, Connection con) {
		try {
			if (rs != null)
				rs.close();
			if (pstmt != null)
				pstmt.close();
			if (con != null)
				con.close();
			System.out.println("close 성공");
		} catch (SQLException e) {
			System.out.println("close 실패");
			e.printStackTrace();
		}
	} // close end
	
	// rollback(con);
	public static void rollback(Connection con) {
		try {
			con.rollback();
			System.out.println("rollback 성공");
		} catch (SQLException e) {
			System.out.println("rollback 예외");
			e.printStackTrace();
		}
	}

	// commit(con);
	public static void commit(Connection con) {
		try {
			con.commit();
			System.out.println("commit 성공");
		} catch (SQLException e) {
			System.out.println("commit 예외");
			e.printStackTrace();
		}
	}

} // class end

 

- class TransactionTest

- 기존에 TXTest에 있었던 드라이버 연결, 서버 연결, 서버 연결 해제는 JdbcUtil 클래스에 들어갔다.
- 앞서 설명한것처럼 공통적으로 사용되는 메서드를 해당 클래스에서 사용해야하기 때문에 import해준다.

package ex2;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import common.JdbcUtil;

public class TransactionTest {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs=null;
	
	public TransactionTest() {
		con=JdbcUtil.getConnection();
	}
	public void order() {
		boolean isOrderSuccess=false; //tx성공:true, 실패:false
		String sql="INSERT INTO PAY VALUES('ccc','003',1000)";  //성공
		try {
			pstmt=con.prepareStatement(sql);
			int cnt=pstmt.executeUpdate();
			sql="INSERT INTO ORDERLIST VALUES('003','에어컨')"; //성공
			pstmt=con.prepareStatement(sql);
			int cnt2=pstmt.executeUpdate();
			if(cnt!=0 && cnt2!=0) {
				isOrderSuccess=true;
				System.out.println("tx insert 성공");
			}else {
				isOrderSuccess=false; //생략 가능
				System.out.println("tx insert 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("pay insert 예외");
			e.printStackTrace();
		}finally {
			if(isOrderSuccess) {
				JdbcUtil.commit(con);  //사용자 정의 메소드
			}else {
				JdbcUtil.rollback(con);
			}
			JdbcUtil.close(rs, pstmt, con);
		}//finally End
	}//order End
	
}//class End

 

- class TxMain

package ex2;

public class TxMain {

	public static void main(String[] args) {
		TransactionTest tt=new TransactionTest();
		tt.order();  //구매 tx
	}

}

 

- JdbcUtil을 이용해서 PreparedStatementTest와 PstmtMain을 변경해보자.

- TransactionTest와는 다르게 Connection 메서드를 따로 만들지 않고 각각의 삽입, 수정, 검색, 삭제의 메서드에 다음을 앞뒤로 넣어서 수정해서 반영하도록 하자.

		con = JdbcUtil.getConnection();
		} finally {
			JdbcUtil.close(rs, pstmt, con);
		}

 

package ex1;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import common.JdbcUtil;

public class PreparedStatementTest {
	// 필드
	// 여러개의 메서드에서 편하게 사용할 수 있어서 필드에 올려두는게 좋다.
	Connection con;
	ResultSet rs = null;
	PreparedStatement pstmt = null;

	// 데이터 삽입
	public void insert(String id, String pw, String name, int age) {
		con = JdbcUtil.getConnection();
		String sql = "INSERT INTO MEMBER VALUES(?,?,?,?)"; // 보안성 높임
		try {
			pstmt = con.prepareStatement(sql); // 파싱
			pstmt.setNString(1, id);
			pstmt.setNString(2, pw);
			pstmt.setNString(3, name);
			pstmt.setInt(4, age);

			int cnt = pstmt.executeUpdate(); // sql문 실행
			if (cnt > 0) {
				System.out.println("insert 성공");
			} else {
				System.out.println("insert 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("insert 예외");
			e.printStackTrace();
		} finally {
			JdbcUtil.close(rs, pstmt, con);
		}
	} // insert end

	// 데이터 검색
	public List<Member> select() {
		con = JdbcUtil.getConnection();
		try {
			String sql = "SELECT * FROM MEMBER";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			List<Member> mList = new ArrayList<>();
			Member mb = null;
			while (rs.next()) {
				mb = new Member(); // 인스턴스 생성
				mb.setId(rs.getNString("ID"));
				mb.setPw(rs.getNString("PW"));
				mb.setName(rs.getNString("NAME"));
				mb.setAge(rs.getInt("Age"));
				mList.add(mb); // 데이터 축적
			}
			return mList;
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("select 예외");
			e.printStackTrace();
		} finally {
			JdbcUtil.close(rs, pstmt, con);
		}
		return null;
	} // select end

	// 데이터 수정
	public void update(String id, String pw, int age) {
		con = JdbcUtil.getConnection();
		String sql = "UPDATE MEMBER SET PW=?,AGE=? WHERE ID=?";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setNString(1, pw);
			pstmt.setInt(2, age);
			pstmt.setNString(3, id);
			int cnt = pstmt.executeUpdate();
			if (cnt > 0) {
				con.commit();
				System.out.println("update 성공");
			} else {
				System.out.println("update 실패");
				con.rollback();
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("update 예외");
			e.printStackTrace();
		} finally {
			JdbcUtil.close(rs, pstmt, con);
		}
	}

	// 데이터 삭제
	public void delete(String id) {
		con = JdbcUtil.getConnection();
		String sql = "DELETE FROM MEMBER WHERE ID=?";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setNString(1, id);
			int cnt = pstmt.executeUpdate();
			if (cnt > 0) {
				System.out.println("delete 성공");
			} else {
				System.out.println("delete 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("delete 예외");
			e.printStackTrace();
		} finally {
			JdbcUtil.close(rs, pstmt, con);
		}
	}

	// 데이터 삭제

} // class end

 

package ex1;

import java.util.List;

public class PstmtMain {

	public static void main(String[] args) {
		PreparedStatementTest pt = new PreparedStatementTest();
		pt.update("bbb", "4444", 30);
		List<Member> mList = pt.select();
		if (mList.size() != 0) {
			for (Member mb : mList) {
				System.out.println(mb); //회원리스트 출력
			}
		}
	}

}

 

- 공통 클래스를 이용한 연습

- class Practice

package ex3;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import common.JdbcUtil;

public class Practice {
	Connection con;
	ResultSet rs = null;
	PreparedStatement pstmt;

	public Practice() {
		con = JdbcUtil.getConnection();
	}

	public void order() {
		boolean isReviewSuccess = false;
		String sql = "INSERT INTO REVIEW VALUES('bbb','002','BAD')";
		try {
			pstmt = con.prepareStatement(sql);
			int cnt = pstmt.executeUpdate();
			sql = "INSERT INTO PRODUCT VALUES('002','TV')";
			pstmt = con.prepareStatement(sql);
			int cnt2 = pstmt.executeUpdate();
			if (cnt > 0 && cnt2 > 0) {
				isReviewSuccess = true;
				System.out.println("tx insert 성공");
			} else {
				System.out.println("tx insert 실패");
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			System.out.println("insert 예외");
			e.printStackTrace();
		} finally {
			if (isReviewSuccess) {
				JdbcUtil.commit(con);
			} else {
				JdbcUtil.rollback(con);
			}
			JdbcUtil.close(rs, pstmt, con);
		}
	}

}

 

- class PracticeMain

package ex3;

public class PracticeMain {

	public static void main(String[] args) {
		Practice pt = new Practice();
		pt.order();
	}
}

'ICIA 수업일지' 카테고리의 다른 글

2021.07.15 수업일지  (0) 2021.07.17
2021.07.14 수업일지  (0) 2021.07.17
2021.07.12 수업일지  (0) 2021.07.17
2021.07.09 수업일지  (0) 2021.07.12
2021.07.08 수업일지  (0) 2021.07.10