티스토리 뷰

Transaction ? 

 

데이터베이스 작업의 최소단위를 말한다.

 

주로 insert, update, delete 등 database 에 변화가 생기는 작업에 트랜젝션이 필요할 것이다.

 

예를들면 은행의 계좌이체 이벤트에서 A -> B 로 10000원을 이체한다고 가정하자.

 

  1. A계좌에서 10000원이 차감된다.
  2. B계좌에 10000원이 증가한다.

가 하나의 완성된 계좌이체 트랜잭션일 것이다.

 

하지만 2번과정에서 에러가 발생해 A계좌에서 10000원이 차감되고 B계좌에 10000원이 증가하지 않았다면, A의 10000원은 공중분해된것과 같은 결과일 것이다.

 

계좌이체 트랜잭션에서는 이러한 에러가 발생했을시에 1번 이벤트를 다시 취소 (rollback) 시켜야 할 것이다.

 

 


Spring에서의 @Transactional

 

@Transactional 어노테이션이 걸려있는 메서드는, 그 메서드의 모든 작업중에 에러가 하나라도 발생할 시 작업을 모두 rollback 시킨다! 개꿀!!!

 

 


포스팅에 앞서...

이 포스팅은 Spring Framework 를 이용한 Java 코드 위주의 설명입니다.

 

관련 코드는 아래 링크를 통해 깃허브에서 받아보실 수 있습니다.

 

https://github.com/ChoHyeonJunn/Workspace_Spring

 

ChoHyeonJunn/Workspace_Spring

Contribute to ChoHyeonJunn/Workspace_Spring development by creating an account on GitHub.

github.com


SpringMVC03
1. pom.xml : dependency (ojdbc6(+ repository), mybatis, mybatis-spring, commons-dbcp, spring-orm)
2. web.xml : applicatiionContext.xml, mapping(*.do), encoding filter
3. /WEB-INF/spring/sqls/myboard.sql
4. DTO, DAO, BIZ, CONTROLLER
5. src/main/resources/mybatis/board-mapper.xml
6. src/main/resources/mybatis/db.properties
7. /WEB-INF/spring/sqls/config.xml
8. applicationContext.xml, servlet-context.xml

 

_filter
9. com/mvc/upgrade/common/filter/LogFilter (impl javax.servlet.Filter)
10. web.xml : filter

_aop
11. pom.xml : aspectjweaver, aspectjrt
12. com/mvc/upgrade/common/aop/LogAop
13. WEB-INF/spring/appServlet/aop-context.xml
14. web.xml : aop-context.xml 추가 (init-param)
15. src/main/resources/log4j.xml (logger 추가 및 log level 변경 - trace)

_login
16. pom.xml : jackson-core-asl, jackson-mapper-asl (Spring 4.x 이후부터는 변경됨)
17. WEB-INF/spring/sqls/mymbmer.sql
18. dto, dao, biz, controller
19. src/main/resources/mybatis/member-mapper.xml
20. WEB-INF/spring/sqls/config.xml

_interceptor
21. com/mvc/upgrade/common/interceptor/LoginInterceptor (impl HadlerInterceptor)
22. servlet-context.xml : interceptor 추가


_transaction
23. (Board) dao, biz, controller
24. servlet-context.xml : tx(nameapce) ->  추가 (aop 로 동작하는것!)
25. applicationContext.xml : transactionManager 빈 객체 생성!



23. (Board) dao, biz, controller 

 

트랜잭션 처리를 할 만한 과정을 하나 추가한다. 여기서는 test라는 요청과 메서드를 등록하도록 하겠다.

 

<index.jsp> test.do 추가

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1><a href="list.do">LIST...</a></h1>
	
	<a href="home.do">HOME</a>
	
	<a href="joinform.do">JOIN</a>
	<a href="loginform.do">LOGIN</a>
	
	<a href="test.do">TRANSACTION TEST</a>
</body>
</html>

 

<HomeController.java> test.do 를 처리할 메서드 추가

	@RequestMapping(value = "/test.do")
	public String test() {

		logger.info("TRANSACTION");
		biz.test();

		return "redirect:list.do";
	}

 

<BoardBiz.java><BoardBizImpl.java> @Transactional 어노테이션 추가하여 test메서드 추가

	@Transactional
	@Override
	public String test() {

		// dummy insert
		dao.insert(new BoardDto(1000, "test", "test", "test", null));

		// exception 발생 !! -> 위의 dummy insert는 rollback 되어야함!
		String test = dao.test();
		int lenth = test.length();

		return null;
	}

 

<BoardDao.java><BoardDaoImpl.java> test 메서드 추가

	@Override
	public String test() {
		return null;
	}

dao 에서 리턴값은 null 이다!! 그러면 biz에서 dao.test()를 호출하고 리턴받은값의 length() 를 호출할 때 nullPointerException 이 발생할 것이다!

 

트랜잭션의 개념에서 test()라는 메소드 안의 작업중 어떠한 작업 하나라도 에러가 발생할 시 모든 작업은 rollback 되어야 한다. 따라서 biz 에서 dao.insert() 작업 또한 rollback 되어야 한다.

 

Spring에서는 트랜잭션 처리할 메서드에 @Transactional 이라는 어노테이션을 달아주면 이러한 작업을 알아서 해준다!!

 

이 트랜잭션 작업을 위한 Spring 설정을 알아보도록 하겠다.

 



24. servlet-context.xml : tx(nameapce) ->  추가 (aop 로 동작하는것!) 

 

Namespaces 에서 tx 추가!

 

Source에 <tx:annotation-driven/> 추가! 

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.mvc.upgrade" />
	
	<!-- 인터셉터 객체 생성 -->
    <beans:bean id="loginInterceptor" class="com.mvc.upgrade.common.interceptor.LoginInterceptor">
    </beans:bean>
    <!-- Interceptor 설정 -->
    <interceptors>
        <interceptor>
            <!-- <mapping path="/insertpage.do"/>
            <mapping path="/insert.do"/>
            <mapping path="/updatepage.do"/>
            <mapping path="/update.do"/>
            <mapping path="/delete.do"/> -->
            <mapping path="/*"/>
            <beans:ref bean="loginInterceptor"/>
        </interceptor>
    </interceptors>

	<!-- 트랜잭션 처리 -->
	<tx:annotation-driven/>
	
</beans:beans>

 

 

 



25. applicationContext.xml : transactionManager 빈 객체 생성! 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	<!-- db.properties -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:mybatis/db.properties</value>
				<!-- classpath = src/main/resources 를 잡아준다. -->
			</list>
		</property>
	</bean>
	
	<!-- dataSource -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="${driver}"/>
		<property name="url" value="${url}"/>
		<property name="username" value="${username}"/>
		<property name="password" value="${password}"/>
	</bean>
	
	<!-- mybatis -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="WEB-INF/spring/sqls/config.xml"/>
	</bean>
	
	<!-- sqlSessoinTemplate -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSession"/>
	</bean>
	
	<!-- transaction -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	
</beans>





위 과정을 거치고 나면 transaction 이벤트 발생시 nullPointerException 이 발생하고 db에 insert되는 과정이 취소될 것이다.

 

BoardBizImpl 에 @Transactional 어노테이션을 달았다 없앴다 하며 test 해보겠습니다~!

 

<index.jsp> 트랜잭션 이벤트는 TRANSACTION TEST 라는 링크를 클릭하면 발생한다.

<selectList.jsp> 일단 테이블에는 아래와같은 데이터가 저장되어있습니다.

 

index.jsp에서 TRANSACTION TEST 링크 클릭시 다음과 같은 에러가 발생합니다! 

혹시나 로그인창이 떠버린다면 com.mvc.upgrade.common.interceptor.LoginInterceptor.java 에서 다음과 같이 test.do URI를 추가해주면 됩니다.

 

 

eclipse 의 console 창의 내용은 다음과 같습니다.

 

TRANSACTION TEST 링크의 test.do 요청은 게시물 리스트에 글을 하나 추가하는 것이었고, 트랜잭션 처리 중 에러 발생 시 db에 insert된 row 는 다시 rollback 되어야 합니다.

 

콘솔창을 보면 insert가 정상적으로 이루어진 후, 에러가 발생하여 다시 롤백되었다는 표시들을 볼 수 있습니다.

 

list 창으로 가봐도 test 라는 글이 등록되지 않을 것을 확인할 수 있습니다.

 

그렇다면 @Transactional 이라는 어노테이션을 주석처리하고 요청이 어떻게 발생하는지 확인해보도록 하겠습니다.

 

<BoardBizImpl.java> @Transactional 주석처리

	//@Transactional
	@Override
	public String test() {

		// dummy insert
		dao.insert(new BoardDto(1000, "test", "test", "test", null));

		// exception 발생 !! -> 위의 dummy insert는 rollback 되어야함!
		String test = dao.test();
		int lenth = test.length();

		return null;
	}

 

똑같은 요청을 발생시키면 에러가 발생하고 글 등록까지 완료된 모습을 볼 수 있습니다.

 


이처럼 트랜잭션 처리가 필요한 메서드에 Spring에서는 몇가지 설정과 어노테이션 하나로 rollback 처리를 편안하게 실행할 수 있습니다.

'JAVA > Spring' 카테고리의 다른 글

Spring 04 - Annotation  (0) 2020.03.18
Spring 03 - Spring Bean (Collection)  (0) 2020.03.18
Spring 02 - Spring Bean  (0) 2020.03.18
Spring 01 - 기본개념 / 기본환경설정  (0) 2020.03.18
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함