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 |