은행 계좌이체시 잔액이 옮겨지는 것을 이용한 트랜잭션 이해 예제이다.
1번 은행용 Bank1.java코드
package vo;
public class Bank1 {
private int bid;
private String bname;
private int balance;
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Bank1 [bid=" + bid + ", bname=" + bname + ", balance=" + balance + "]";
}
}
2번 은행은 위에서 클래스명만 다르니 올리진 않겠다.
Bank1DAO.java 코드
현재는 한방향으로 Bank1 → Bank2 로만 송금이 된다는 조건이다.
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import util.JDBCUtil;
import vo.Bank1;
public class Bank1DAO {
Connection conn;
PreparedStatement pstmt;
final String sql_transfer1="UPDATE BANK1 SET BALANCE=BALANCE-? WHERE BID=101";
final String sql_transfer2="UPDATE BANK2 SET BALANCE=BALANCE+? WHERE BID=222";
public boolean transfer(int balance) {
// DAO의 메서드는 일반적으로 vo
// 강제적으로 자료형,인자의 개수를 고정할수도있음!
conn=JDBCUtil.connect();
try {
conn.setAutoCommit(false);
// 트랜잭션의 시작을 설정하는 메서드
// 자동commit을 해제할수있음(MySQL)
// +++하나의 작업단위+++
pstmt=conn.prepareStatement(sql_transfer1);
pstmt.setInt(1, balance);
pstmt.executeUpdate();
pstmt=conn.prepareStatement(sql_transfer2);
pstmt.setInt(1, balance);
pstmt.executeUpdate();
// +++하나의 작업단위+++
System.out.println("수행");
pstmt=conn.prepareStatement(sql_selectOne);
ResultSet rs=pstmt.executeQuery();
rs.next();
System.out.println(rs.getString("BNAME")+" | "+rs.getInt("BALANCE"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
rs.close();
pstmt=conn.prepareStatement(sql_selectOne);
rs=pstmt.executeQuery();
rs.next();
if(rs.getInt("BALANCE")<0) { // 가진금액보다 더많이 계좌이체를 하려고할때
conn.rollback();
return false;
}
else {
conn.commit();
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
return true;
}
final String sql_selectOne="SELECT * FROM BANK1 WHERE BID=101";
public Bank1 selectOne(Bank1 vo) {
Bank1 data=null;
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_selectOne);
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
data=new Bank1();
data.setBalance(rs.getInt("BALANCE"));
data.setBid(rs.getInt("BID"));
data.setBname(rs.getString("BNAME"));
System.out.println("Bank1DAO: selectOne(): "+data);
return data;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
return data;
}
}
Bank2DAO.java 코드
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import util.JDBCUtil;
import vo.Bank2;
public class Bank2DAO {
Connection conn;
PreparedStatement pstmt;
final String sql_selectOne="SELECT * FROM BANK2 WHERE BID=222";
public Bank2 selectOne(Bank2 vo) {
Bank2 data=null;
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_selectOne);
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
data=new Bank2();
data.setBalance(rs.getInt("BALANCE"));
data.setBid(rs.getInt("BID"));
data.setBname(rs.getString("BNAME"));
System.out.println("Bank2DAO: selectOne(): "+data);
// 어디서 잘못됐는지 확인이 편한 위치의 로그
// selectOne이 잘 됐으면 V나 C 잘못인거지..
return data;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
return data;
}
}
위에 DAO 코드들에는 각각의 멤버변수들을 볼 수 있게 selectOne이 포함되어있다.
. jsp 코드1
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>view</title>
</head>
<body>
신한: ${b1.name} | ${b1.balance}원 <br>
국민: ${b2.name} | ${b2.balance}원
<hr>
<form method="post">
이체할 금액: <input type="number" value="0" min="0" name="balance">원
<input type="submit" value="계좌이체">
</form>
</body>
</html>
post 방식으로 form에 입력한 값을 .jsp 2번째 파일로 넘겨주면
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="b1" class="vo.Bank1" />
<jsp:useBean id="b2" class="vo.Bank2" />
<jsp:useBean id="dao1" class="dao.Bank1DAO" />
<jsp:useBean id="dao2" class="dao.Bank2DAO" />
<% //null은 parseInt 할 수 없으니 유의!
if(dao1.transfer(Integer.parseInt(request.getParameter("balance")))){
out.print("<script>alert('성공!');location.href='NEWFILE.JPS'</script>");
}
else{
out.print("<script>alert('실패...');</script>");
}
b1=dao1.selectOne(b1);
b2=dao2.selectOne(b2);
session.setAttribute("b1", b1); // V에서 EL식으로 출력하기 위해
session.setAttribute("b2", b2); // JSP scoper 내장객체에 setAttribute 함
%>
성공시 다시 location.href를 통해 1번 jsp 파일로 이동시켜준다.
'개발자노트 > 웹' 카테고리의 다른 글
HTML - FrontController (0) | 2022.08.23 |
---|---|
초기화 매개변수 (xml) (0) | 2022.08.18 |
트랜잭션 transaction (0) | 2022.08.17 |
HTML - JSP - 커스텀태그를 사용해 EL식 , JSTL 사용 (0) | 2022.08.16 |
HTML - JSP - 커스텀태그 import / redirect / url (0) | 2022.08.16 |