트랜잭션(Transaction)
- 여러 개의 DML 명령문을 하나의 논리적인 작업 단위로 묶어서 관리하는 것
- All 또는 Nothing 방식으로 작업 처리 -> 작업의 일관성 유지
- 웹 애플리케이션에선 Service 클래스의 각 메서드가 애플리케이션의 단위 기능을 수행
웹 애플리케이션에서 묶어서 처리하는 단위 기능 예시
- 게시판 글 조회 시 해당 글을 조회하는 기능/ 조회 수를 갱신하는 기능
- 쇼핑몰에서 상품 주문 시 주문 상품을 테이블에 등록하는 기능/ 주문자의 포인트를 갱신하는 기능
- 은행에서 송금 시 송금자의 잔고를 갱신하는 기능/ 수신자의 잔고를 갱신하는 기능
스프링의 트랜잭션 속성
property | function |
propagation | 트랜잭션 전파 규칙 설정 |
isolation | 트랜잭션 격리 레벨 설정 |
readOnly | 읽기 전용 여부 설정 |
rollbackFor | 트랜젝션을 롤백(rollback)할 예외 타입 설정 |
norollbackFor | 트랜잭션을 콜백하지 않을 예외 타입 설정 |
timeout | 트랜잭션 타입아웃 시간 설정 |
propagation속성이 갖는 값
값 | 의미 |
REQUIRED | - 트랜잭션 필요, 진행 중인 트랜잭션이 있는 경우 해당 트랜잭션 사용 - 트랜잭션이 없으면 새로운 트랜잭션 생성, 디폴트 값 |
MANDATORY | - 트랜잭션 필요 - 진행 중인 트랜잭션이 없는 경우 예외 발생 |
REQUIRED_NEW | - 항상 새로운 트랜잭션 생성 - 진행 중인 트랜잭션이 있는 경우 기존 트랜잭션을 일시 중지시킨 후 새로운 트랜잭션 시작 - 새로 시작된 트랜잭션이 종료되면 기존 트랜잭션 계속 진행 |
SUPPORTS | - 트랜잭션 필요 없음 - 진행 중인 트랜잭션이 있는 경우 해당 트랜잭션 사용 |
NOT_SUPPORTED | - 트랜잭션 필요 없음 - 진행 중인 트랜잭션이 있는 경우 기존 트랜잭션을 일시 중지시킨 후 메서드 실행 - 메서드 실행이 종료되면 기존 트랜잭션 계속 진행 |
NEVER | - 트랜잭션 필요 없음 - 진행 중인 트랜잭션이 있는 경우 예외 발생 |
NESTED | - 트랜잭션 필요 - 진행 중인 트랜잭션이 있는 경우 기존 트랜잭션에 중첩된 트랜잭션에서 메서드 실행 - 트랜잭션이 없으면 새로운 트랜잭션 생성 |
isolation속성이 갖는 값
값 | 의미 |
DEFAULT | 데이터베이스에서 제공하는 기본 설정 사용 |
READ_UNCOMMITED | 다른 트랜잭션에서 커밋하지 않은 데이터 읽기 가능 |
READ_COMMITED | 커밋한 데이터만 읽기 가능 |
REPEATABLE_READ | 현재 트랜잭션에서 데이터를 수정하지 않았다면 처음 읽어온 데이터와 두 번째 읽어온 데이터가 동일 |
SERIALIZABLE | 같은 데이터에 대해 한 개의 트랜잭션만 수행 가능 |
스프링 트랜잭션 기능 실습 #1
데이터베이스 명 새로 만들고, 테이블(cust_account) 생성.
USE customer;
CREATE TABLE cust_account(
accountNo VARCHAR(20) PRIMARY KEY,
custName VARCHAR(50),
balance DOUBLE(20,4)
);
INSERT INTO cust_account(accountNo,custName,balance)
VALUES('70-490-930','홍길동',10000000);
INSERT INTO cust_account(accountNo,custName,balance)
VALUES('70-490-911','김유신',10000000);
COMMIT;
SELECT * FROM cust_account;
accountNo : 계좌 번호
custName : 예금자
balance : 계좌잔고
insert문실행 후 반드시 commit하기.
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/account/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="accController"
class="com.spring.account.AccountController">
<property name="methodNameResolver">
<ref local="MethodResolver" />
</property>
<property name="accService" ref="accService" />
</bean>
<bean id="MethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/account/sendMoney.do">sendMoney</prop>
</props>
</property>
</bean>
<bean id="UrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/account/*.do">accController</prop>
</props>
</property>
</bean>
</beans>
action-servlet.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>/WEB-INF/config/jdbc.properties</value>
</property>
</bean>
<bean id="dataSource"
class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--<property name="configLocation" value="classpath:mybatis/model/modelConfig.xml" />-->
<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml" />
</bean>
<bean id="sqlSession"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<bean id="accDAO"
class="com.spring.account.AccountDAO">
<property name="sqlSession" ref="sqlSession" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
action-mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="accService"
class="com.spring.account.AccountService">
<property name="accDAO" ref="accDAO" />
</bean>
</beans>
action-service.xml
jdbc.driverClassName=org.mariadb.jdbc.Driver
jdbc.url=jdbc:mariadb://localhost:3306/customer
jdbc.username=root
jdbc.password=1234
jdbc.properties
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.account">
<update id="updateBalance1">
<![CDATA[
update cust_account
set balance=balance-5000000
where accountNo = '70-490-930'
]]>
</update>
<update id="updateBalance2">
<![CDATA[
update cust_account
set balance=balance+5000000
where accountNo = '70-490-911'
]]>
</update>
</mapper>
account.xml
package com.spring.account;
public class AccountVO {
private String accountNo;
private String custName;
private int balance;
public AccountVO() {
//System.out.println("MemberVO 생성자 호출(객체 생성)");
}
public AccountVO(String accountNo, String custName, int balance) {
this.accountNo = accountNo;
this.custName = custName;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
AccountVO.java
package com.spring.account;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
public class AccountController extends MultiActionController {
private AccountService accService;
public void setAccService(AccountService accService) {
this.accService = accService;
}
public ModelAndView sendMoney(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView();
accService.sendMoney();
mav.setViewName("result");
return mav;
}
}
AccountController.java
package com.spring.account;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Transactional(propagation=Propagation.REQUIRED)
public class AccountService {
private AccountDAO accDAO;
public void setAccDAO(AccountDAO accDAO) {
this.accDAO = accDAO;
}
public void sendMoney() throws Exception {
accDAO.updateBalance1();
accDAO.updateBalance2();
}
}
AccountService.java
package com.spring.account;
import org.apache.ibatis.session.SqlSession;
import org.springframework.dao.DataAccessException;
public class AccountDAO {
private SqlSession sqlSession;
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public void updateBalance1() throws DataAccessException {
sqlSession.update("mapper.account.updateBalance1");
}
public void updateBalance2() throws DataAccessException {
sqlSession.update("mapper.account.updateBalance2");
}
}
AccountDAO.java
WEB-INF폴더 안에 views폴더-account폴더 생성
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<% request.setCharacterEncoding("utf-8"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>결과창</title>
</head>
<body>
<h1>송금이 완료되었습니다. </h1>
</body>
</html>
result.jsp
-- 결과 --
↓↓↓↓↓
'Spring' 카테고리의 다른 글
Spring #11 : 다중 파일 업로드 (230127) (0) | 2023.01.27 |
---|---|
Spring #9 : 메이븐과 스프링 STS (230125) (0) | 2023.01.25 |
Spring #7 : 스프링-마이바티스 연동(추가)(230120) (0) | 2023.01.20 |
Spring #6 : 스프링-마이바티스 연동(230119) (0) | 2023.01.20 |
Spring #5 : 마이바티스 - 동적 SQL문(230118) (0) | 2023.01.18 |
댓글