๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring/Spring Quick Start

ํŠธ๋žœ์žญ์…˜(Transaction) ์ ์šฉ

 

1. ํŠธ๋žœ์žญ์…˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋“ฑ๋ก

ํŠธ๋žœ์žญ์…˜์„ ์œ„ํ•ด xmlns:tx๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

[ applicationContext.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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

	<context:component-scan base-package="com.springbook.biz" />

	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

	<!-- DataSource ์„ค์ • -->
	<context:property-placeholder location="classpath:config/database.properties" />

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<!-- Spring JDBC ์„ค์ • -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
</beans>

2. ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์ž ๋“ฑ๋ก

๋ชจ๋“  Transaction ๊ด€๋ฆฌ์ž๋Š” PlatformTransactionManager interface๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์ด๋‹ค.

๋ชจ๋“  Transaction ๊ด€๋ฆฌ์ž๋Š” Transaction ๊ด€๋ฆฌ์— ํ•„์š”ํ•œ commit(), rollback() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

public interface PlatformTransactionManager{
	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}

JDBC๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— DataSourceTranscationManager ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ–ˆ๋‹ค.

JPA๋ฅผ ์ด์šฉํ•˜์—ฌ DAO ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด JPATransactionManager๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด DataSourceTranscationManager ํด๋ž˜์Šค๋ฅผ <bean> ๋“ฑ๋กํ•œ๋‹ค.

[ applicationContext.xml ์ค‘ ์ถ”๊ฐ€ ]
	<!-- Transaction ์„ค์ • -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋‹ค๊ฐ€ "์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑ"ํ•˜๊ณ  "๋ฌธ์ œ์—†์ด ์ •์ƒ์œผ๋กœ ์ˆ˜ํ–‰ ์ข…๋ฃŒ๋˜๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹"ํ•˜๋ฉด ๋œ๋‹ค.

3. ํŠธ๋žœ์žญ์…˜ Advice ์„ค์ •

ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋Š” <tx:advice> ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•œ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์˜ ์–ด๋“œ๋ฐ”์ด์Šค ํด๋ž˜์Šค๋Š” ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š”๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ <tx:advice> ์„ค์ •์„ ์ฐธ์กฐํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

[ applicationContext.xml ์ค‘ ์ถ”๊ฐ€ ]
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>

์ด ๋ง์€ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ์–ด๋“œ๋ฐ”์ด์Šค ๊ฐ์ฒด์— ํด๋ž˜์Šค ์ด๋ฆ„์ด๋‚˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ์ด๊ธฐ๋„ ํ•˜๋‹ค.

๋‹จ์ง€ ์–ด๋“œ๋ฐ”์ด์Šค์˜ ์•„์ด๋””๋ฅผ id ์†์„ฑ์œผ๋กœ, ์–ด๋“œ๋ฐ”์ด์Šค ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉํ•  ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์ž๋ฅผ transaction-manager ์†์„ฑ์œผ๋กœ ์ง€์ •ํ•  ๋ฟ์ด๋‹ค!

์œ„ ์„ค์ •์€ get์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋Š” ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•œ๋‹ค.

๊ทธ ์™ธ ๋‚˜๋จธ์ง€ ๋ฉ”์†Œ๋“œ๋“ค์„ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์— ํฌํ•จํ–ˆ๋‹ค๋Š” ๋œป์ด๋‹ค.

4. <aop:advisor> ํŠธ๋žœ์žญ์…˜ ์ ์šฉ

<aop:advisor>์™€ <aop:aspect>๋Š” ๊ฐ™์€ ๊ธฐ๋Šฅ์˜ ์—˜๋ฆฌ๋จผํŠธ์ด๋‹ค. ํฌ์ธํŠธ์ปท๊ณผ ์–ด๋“œ๋ฐ”์ด์Šค์˜ ๊ฒฐํ•ฉ์„ ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์™œ ๋‘˜๋กœ ๋‚˜๋‰˜์—ˆ์„๊นŒ?

 <aop:aspect> ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํฌ์ธํŠธ์ปท๊ณผ ๊ฒฐํ•ฉํ•  ์–ด๋“œ๋ฐ”์ด์Šค ๊ฐ์ฒด์˜ ์•„์ด๋””์™€ ์–ด๋“œ๋ฐ”์ด์Šค ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ์•Œ์•„์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ์–ด๋“œ๋ฐ”์ด์Šค๋Š” ์œ„์™€ ๊ฐ™์ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, ์–ด๋“œ๋ฐ”์ด์Šค ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ๋ชฐ๋ผ์„œ <aop:aspect> ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋ž˜์„œ <aop:advisor>๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>
	
	<aop:config>
		<aop:pointcut id="txPointcut"  expression="execution(* com.springbook.biz..*(..))"/>
		
		<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
	</aop:config>

์†Œ์Šค์ฝ”๋“œ ํ•œ๋ฒˆ์— ๋ณด๊ธฐ

ํŠธ๋žœ์žญ์…˜ ์„ค์ •์ด ์™„๋ฃŒ๋œ ์ „์ฒด ์†Œ์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

[ applicationContext.xml ]
<!-- DataSource ์„ค์ • -->
<context:property-placeholder location="classpath:config/database.properties" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
	destroy-method="close">
	<property name="driverClassName" value="${jdbc.driver}" />
	<property name="url" value="${jdbc.url}" />
	<property name="username" value="${jdbc.username}" />
	<property name="password" value="${jdbc.password}" />
</bean>

<!-- Spring JDBC ์„ค์ • -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<property name="dataSource" ref="dataSource" />
</bean>

<!-- Transaction ์„ค์ • -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
	<tx:attributes>
		<tx:method name="get*" read-only="true"/>
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut id="txPointcut"  expression="execution(* com.springbook.biz..*(..))"/>
	
	<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
</aop:config>

์ •๋ฆฌ: ์–ด๋–ค ์ˆœ์„œ๋กœ ๋™์ž‘ํ•˜๋Š”๊ฐ€?

โ‘  ํด๋ผ์ด์–ธํŠธ๊ฐ€ BoardServiceImpl ๊ฐ์ฒด์˜ insert() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, โ‘ก insertBoard() ๋ฉ”์†Œ๋“œ์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ˆ˜ํ–‰๋œ๋‹ค.

๋งŒ์•ฝ insertBoard() ์ˆ˜ํ–‰ ์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด โ‘ข txAdvice๋กœ ๋“ฑ๋กํ•œ ์–ด๋“œ๋ฐ”์ด์Šค๊ฐ€ ๋™์ž‘ํ•˜์—ฌ โ‘ฃ txManager์˜ rollback() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๋งŒ์•ฝ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค๋ฉด commit() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.