트랜잭션이란!??!?!!?!??!

2023. 6. 22. 16:19·백/spring

1. 트랜잭션의 개념

논리적 단위로 어떤 한 부분의 작업이 완료되었다 하더라도 , 다른 부분의 작업이 완료되지 않을 경우 전체 취소되는 것입니다. 이때 , 작업이 완료되는 것을 커밋(commit)이라고 하고 , 작업이 취소되는 것을 롤백(rollback)이라고 합니다. 영화 예매를 할 경우 카드 결제 작업과 마일리지 적립 작업

2. 스프링 트랜잭션 사용방법

트랜잭션 처리를 하지 않았을 경우 rollback이 되지 않는 경우입니다

조건에 안 맞는 데이터가 들어왔을때 '매표소 직원' 테이블에는 제약조건에 걸린 값만 들어오지만

'카드 결제' 컬럼에선 제약조건이 없기때문에 그 데이터가 그대로 남아있다 => 문제생김!

3. 스프링 트랜잭션을 이용하기 위한 설정

*. servlet-context.xml
<beans:bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<beans:property name="dataSource" ref="dataSource"></beans:property>
</beans:bean>
<beans:bean name="dao" class="com.javalec.spring_tran_apply.dao.TicketDao" >
<beans:property name="template" ref="template" />
<beans:property name="transactionManager" ref="transactionManager"></beans:property>
</beans:bean>

*. Dao
PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void buyTicket(final TicketDto dto) {
TransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);
try {
template.update(new PreparedStatementCreator() {
}
});
template.update(new PreparedStatementCreator() {
}
});
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}

 

실습

select * from card;
select * from ticket;

CREATE TABLE card 
(consumerId VARCHAR2(10)
, amount NUMBER(1)
);

CREATE TABLE ticket 
(consumerId VARCHAR2(10)
, countnum NUMBER(1) CHECK(countnum < 5)
);

제약조건 건 테이블 하나, 그냥 테이블 하나 생성

 

<!-- JDBC Template -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.1.4.RELEASE</version>
		</dependency>

		<!--lombok-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.24</version>
			<scope>provided</scope>
		</dependency>

프로젝트에 디펜던시 추가

<!--	dataSource 객체는 데이터 베이스 정보 포함-->
	<beans:bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<beans:property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<beans:property name="username" value="scott"/>
		<beans:property name="password" value="tiger"/>
	</beans:bean>

<!--	JdbcTemplate 객체에 dataSource 객체를 포함-->
	<beans:bean name="template" class="org.springframework.jdbc.core.JdbcTemplate">
		<beans:property name="dataSource" ref="dataSource"/>
	</beans:bean>

board _jdbc에 있던 servlet-context 복사

그 밑에

<beans:bean name="dao" class="com.lgy.spring_tran.dao.TicketDao">
<beans:property name="template" ref="template"></beans:property>
</beans:bean>

추가.

package com.lgy.spring_tran.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class TicketDto {
private String consumerId;
// amount 갯수로 대체
// private int countnum;
private int amount;
}

dto

package com.lgy.spring_tran.dao;

import com.lgy.spring_tran.dto.TicketDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@Slf4j
public class TicketDao {
JdbcTemplate template;

public void setTemplate(JdbcTemplate template) {
this.template = template;
}

public void buyTicket(final TicketDto dto){
// 카드결제처리
template.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
log.info("@# 카드 결제 처리");
String query = "insert into card(consumerId, amount) values(?,?)";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, dto.getConsumerId());
pstmt.setInt(2, dto.getAmount());
return pstmt;
}
});

// 티켓 수령
template.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
log.info("@# 티켓 수령");
String query = "insert into ticket(consumerId, countnum) values(?,?)";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, dto.getConsumerId());
pstmt.setInt(2, dto.getAmount());
return pstmt;
}
});
}
}

dao

return "redirect:buy_ticket";
}
@RequestMapping("buy_ticket")
public String buy_ticket(){
log.info("@# buy_ticket()");

return "buy_ticket";
}

homeController return값 바꿔주고 스트링 메소드 만들기

 

<%--
Created by IntelliJ IDEA.
User: GGG
Date: 2023-06-22
Time: 오후 3:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>카드 결제</p>
<form action="buy_ticket_card">
고객 아이디:<input type="text" name="consumerId"><br>
티켓 구매수:<input type="text" name="amount"><br>
<input type="submit" value="구매">
</form>
</body>
</html>

 

package com.lgy.spring_tran;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import com.lgy.spring_tran.dao.TicketDao;
import com.lgy.spring_tran.dto.TicketDto;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestMethod;

/**
* Handles requests for the application home page.
*/
@Controller
@Slf4j
public class HomeController {

private TicketDao dao;

@Autowired
public void setDao(TicketDao dao) {
this.dao = dao;
}

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);

Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

model.addAttribute("serverTime", formattedDate );

return "redirect:buy_ticket";
}
@RequestMapping("buy_ticket")
public String buy_ticket(){
log.info("@# buy_ticket()");

return "buy_ticket";
}

@RequestMapping("buy_ticket_card")
public String buy_ticket_card(TicketDto ticketDto, Model model){
log.info("@# buy_ticket_card()");
log.info("@# ticketDto=>"+ticketDto);

dao.buyTicket(ticketDto);
model.addAttribute("ticketInfo", ticketDto);

return "buy_ticket_end";
}
}

 

<%--
Created by IntelliJ IDEA.
User: GGG
Date: 2023-06-22
Time: 오후 3:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
buy_ticket_end.jsp입니다.<br>
${ticketInfo.consumerId}<br>
${ticketInfo.amount}<br>
</body>
</html>

4장 먼저

위반해보자(5장 넣어보기)

db를 보면?

제약조건없는 card에는 데이터가 뜨고
있는 ticket에는 두번째 입력한 데이터가 안뜸!

///////////////커밋, 롤백 해보기

<!-- DataSourceTransactionManager-->
<beans:bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<beans:property name="dataSource" ref="dataSource"></beans:property>
</beans:bean>
<!-- <beans:bean name="dao" class="com.lgy.spring_tran.dao.TicketDao">-->
<!-- <beans:property name="template" ref="template"></beans:property>-->
<!-- </beans:bean>-->
<beans:bean name="dao" class="com.lgy.spring_tran.dao.TicketDao">
<beans:property name="template" ref="template"></beans:property>

<beans:property name="transactionManager" ref="transactionManager"></beans:property>

</beans:bean>

servlet-context에 추가

 

package com.lgy.spring_tran.dao;

import com.lgy.spring_tran.dto.TicketDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@Slf4j
public class TicketDao {
JdbcTemplate template;

PlatformTransactionManager transactionManager;

public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}

public void setTemplate(JdbcTemplate template) {
this.template = template;
}

public void buyTicket(final TicketDto dto){
TransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);

try {
// 카드결제처리
template.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
log.info("@# 카드 결제 처리");
String query = "insert into card(consumerId, amount) values(?,?)";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, dto.getConsumerId());
pstmt.setInt(2, dto.getAmount());
return pstmt;
}
});

// 티켓 수령
template.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
log.info("@# 티켓 수령");
String query = "insert into ticket(consumerId, countnum) values(?,?)";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, dto.getConsumerId());
pstmt.setInt(2, dto.getAmount());
return pstmt;
}
});
// 문제 없으면 카드 결제 처리, 티켓 수령 동시 처리
transactionManager.commit(status);
}catch (Exception e){
e.printStackTrace();
// 문제 있으면 취소 처리
transactionManager.rollback(status);
}


}
}

 

 

이제 넣으면?

사용자에겐 값이보이나

로그에 violated됬다고써있고

정상 값만 들어가고 비정상값은 롤백되있는것을 확인할 수 있다.

저작자표시 (새창열림)

'백 > spring' 카테고리의 다른 글

스프링 기본파싱전략과 json통신  (1) 2023.07.30
스프링 시큐리티 2- ng처리  (0) 2023.07.12
스프링 시큐리티 1  (0) 2023.07.11
파일 업로드 부터 수정까지  (0) 2023.06.28
Spring Validator를 이용한 검증  (2) 2023.06.22
'백/spring' 카테고리의 다른 글
  • 스프링 시큐리티 2- ng처리
  • 스프링 시큐리티 1
  • 파일 업로드 부터 수정까지
  • Spring Validator를 이용한 검증
니누고
니누고
주니어 개발괴발자
  • 니누고
    진땡이코딩조림
    니누고
  • 전체
    오늘
    어제
    • 분류 전체보기 (93)
      • 편안한코딩생활 (12)
        • 오류 해결 일지 (6)
        • 기타등등 (6)
      • 백 (23)
        • jsp (1)
        • spring boot (7)
        • spring (7)
        • 전자정부프레임워크 (8)
      • 프로젝트 (13)
        • 블로그 제작(중단) (12)
      • 프론트 (3)
        • javascript (3)
      • 데이터베이스 (6)
        • oracle (5)
        • 그 외 (1)
      • cs (6)
        • java (4)
        • cs (1)
        • C (1)
      • 코테 (26)
        • java (25)
        • sql (1)
      • 앱 (0)
        • flutter (0)
        • dart (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    egov
    Java
    mod_jk.log
    Eclipse
    iBatis
    스프링의 기본 파싱전략
    CRUD
    apache
    코딩테스트
    tomcat
    문자열 정렬하기
    함수
    가장 큰 수 찾기
    jpa #springboot
    2017팁스다운
    oracle함수
    중복된 문자 제거
    오블완
    프로그래머스
    Oracle
    배열
    SpringBoot
    대문자와소문자
    카카오 블라인드 채용
    JPA
    spring
    전자정부프레임워크
    배열 회전시키기
    티스토리챌린지
    컴퓨터용량줄이기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
니누고
트랜잭션이란!??!?!!?!??!
상단으로

티스토리툴바