Spring/이론
Transaction 트랜잭션
SEOKIHOUSE
2023. 7. 28. 17:50
Transaction 하기 전 --> 오류나면 transaction1은 실행돼서 db에 저장이 되고 2는 저장이 안된다
에러발생해서 catch문으로 가서 transaction1에만 저장이 된다
practice0728_TransactionX.zip
0.10MB
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>index page</h1>
<hr>
<a href="buy_ticket">티켓사러가기</a>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Buy Ticket</title>
</head>
<body>
<p>카드결제</p>
<form action="buy_ticket_card">
고객 아이디 : <input type="text" name="consumerId"><br>
티켓 구매수 : <input type="text" name="amount"><br>
에러 발생여부 : <input type="text" name="error" value="0"><br>
<input type="submit" value="구매">
</form>
<hr>
에러 발생 여부에 1을 입력하면 에러가 발생합니다.
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>buy_ticket_end페이지</h1>
<hr>
${consumerId }<br>
${amount }<br>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>buy_ticket_error 페이지</h1>
<hr>
<h3>에러가 발생핬습니다</h3>
${consumerId }<br>
${amount }<br>
</body>
</html>
MyController
package com.study.springboot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.study.springboot.service.IBuyTicketService;
@Controller
public class MyController {
@Autowired
IBuyTicketService buyTicket;
@RequestMapping("/")
public String root() {
return "index";
}
@RequestMapping("/buy_ticket")
public String buy_ticket() {
return "buy_ticket";
}
@RequestMapping("/buy_ticket_card")
public String buy_ticket_card(
@RequestParam("consumerId") String consumerId,
@RequestParam("amount")String amount,
@RequestParam("error") String error,
Model model) {
int result = buyTicket.buy(consumerId, Integer.parseInt(amount),error);
model.addAttribute("consumerId", consumerId);
model.addAttribute("amount", amount);
if(result ==1) {
return "buy_ticket_end";
}else {
return "buy_ticket_error";
}
}
}
dao interface
package com.study.springboot.dao;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ITransaction1Dao {
public void pay(String consumerId, int amount);
}
package com.study.springboot.dao;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ITransaction2Dao {
public void pay(String consumerId, int amount);
}
dto
package com.study.springboot.dto;
import lombok.Data;
@Data
public class Transaction1Dto {
private String consumerId;
private int amount;
}
package com.study.springboot.dto;
import lombok.Data;
@Data
public class Transaction2Dto {
private String consumerId;
private int amount;
}
service
package com.study.springboot.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.study.springboot.dao.ITransaction1Dao;
import com.study.springboot.dao.ITransaction2Dao;
@Service
public class BuyTicketService implements IBuyTicketService{
@Autowired
ITransaction1Dao transaction1;
@Autowired
ITransaction2Dao transaction2;
@Override
public int buy(String consumerId, int money, String error) {
try {
transaction1.pay(consumerId, money);
if(error.equals("1")) {
int n = 10/0;
}
transaction2.pay(consumerId, money);
return 1;
} catch (Exception e) {
return 0;
}
}
}
package com.study.springboot.service;
public interface IBuyTicketService {
public int buy(String consumerId, int money, String error);
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.springboot.dao.ITransaction1Dao">
<insert id="pay">
INSERT INTO transaction1 VALUES (#{param1}, #{param2})
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.springboot.dao.ITransaction2Dao">
<insert id="pay">
INSERT INTO transaction2 VALUES (#{param1}, #{param2})
</insert>
</mapper>
▲▲▲ 트랜잭션 미사용 ▲▲▲
- 위에꺼로 하면 에러가 나면 1은 저장되고 2는 저장안된다
▼▼▼트랜잭션 사용 ▼▼▼
- PlatformTransactionManager는 스프링에서 트랜잭션을 관리하는 역할을 수행하는 인터페이스
- TransactionDefinition은 트랜잭션 속성을 정의하는 인터페이스입니다. 트랜잭션의 격리 수준, 제한 시간 등의 속성을 정의할 수 있습니다.
- PlatformTransactionManager를 사용하여 트랜잭션을 시작하고, TransactionDefinition로 트랜잭션 속성을 정의한 후, getTransaction() 메소드를 호출하여 새로운 트랜잭션을 시작합니다. 이렇게 얻어진 TransactionStatus는 트랜잭션의 상태를 나타내며, commit() 메소드로 트랜잭션을 커밋하거나 rollback() 메소드로 트랜잭션을 롤백할 수 있습니다.
- commit() 메소드는 트랜잭션을 성공적으로 종료하고 변경사항을 커밋하는 역할을 합니다.
- rollback() 메소드는 트랜잭션을 실패로 처리하고 변경사항을 롤백하는 역할을 합니다.
따라서, 주어진 BuyTicketService 클래스의 buy() 메소드에서는 두 개의 데이터베이스 작업을 수행하고, 중간에 오류가 발생하는 경우 트랜잭션을 롤백하여 이전 상태로 복원하는 로직이 구현되어 있습니다. 트랜잭션의 상태는 status 변수로 관리되며, 오류가 발생하면 rollback() 메소드를 호출하여 트랜잭션을 롤백하고, 오류가 발생하지 않으면 commit() 메소드를 호출하여 트랜잭션을 커밋합니다. 이를 통해 데이터베이스 작업이 모두 성공적으로 수행되면 변경사항이 커밋되고, 오류가 발생하면 이전 상태로 롤백되는 원자성(Atomicity)을 보장할 수 있습니다.
practice0728_TransactionManager.zip
0.10MB
- 트랜잭션 2번방법 (TransactionTemplate)
- TransactionTemplate은 스프링에서 트랜잭션 처리를 단순화하고 간편하게 사용할 수 있도록 지원하는 클래스입니다. PlatformTransactionManager와 TransactionDefinition를 직접 다루는 대신 TransactionTemplate을 사용하여 트랜잭션을 시작하고, 커밋 또는 롤백하는 로직을 간단하게 구현
- TransactionTemplate은 execute() 메소드를 제공합니다. execute() 메소드는 트랜잭션을 시작하고, 전달된 TransactionCallback 객체를 실행합니다.
- TransactionCallback 객체는 트랜잭션 내에서 실행할 작업을 정의하는 콜백 객체로, doInTransaction() 메소드를 구현해야 합니다.
- TransactionCallbackWithoutResult는 TransactionCallback 인터페이스를 상속한 구체적인 클래스로, 리턴값이 없는 트랜잭션 작업을 수행할 때 사용됩니다. doInTransactionWithoutResult() 메소드에서 트랜잭션 내에서 실행할 작업을 정의합니다.
- 위의 코드에서 TransactionTemplate을 주입받아 tt 변수로 사용합니다. tt.execute()를 호출하여 트랜잭션을 시작하고, 전달된 TransactionCallbackWithoutResult 객체의 doInTransactionWithoutResult() 메소드를 실행합니다.
- doInTransactionWithoutResult() 메소드에서는 transaction1.pay()와 transaction2.pay()를 순차적으로 실행합니다. 만약 error 변수가 "1"이라면, 0으로 나누는 에러를 발생시킵니다. 이로 인해 트랜잭션은 롤백되고, 데이터베이스 작업은 이전 상태로 복원됩니다.
- 트랜잭션 내에서 예외가 발생하면 TransactionTemplate이 자동으로 롤백 처리를 담당하므로 별도의 롤백 코드가 필요하지 않습니다. 예외가 발생하지 않으면 트랜잭션이 커밋되고, 변경사항이 영구적으로 반영됩니다.
- TransactionTemplate를 사용하면 트랜잭션 처리를 간단하게 구현할 수 있으며, TransactionCallbackWithoutResult를 사용하여 리턴값이 없는 트랜잭션 작업을 수행할 수 있습니다.
practice0728_TransactionTemplate.zip
0.10MB
- sql에서 해보자..