<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Transaction on</title><link>https://taetaetae.github.io/tags/transaction/</link><description>Recent content in Transaction on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 08 Jan 2017 17:19:30 +0000</lastBuildDate><atom:link href="https://taetaetae.github.io/tags/transaction/index.xml" rel="self" type="application/rss+xml"/><item><title>Spring Transactional 설정 및 주요속성</title><link>https://taetaetae.github.io/2017/01/08/transactional-setting-and-property/</link><pubDate>Sun, 08 Jan 2017 17:19:30 +0000</pubDate><guid>https://taetaetae.github.io/2017/01/08/transactional-setting-and-property/</guid><description>&lt;p>지난번에는 트랜잭션의 설정값에 대해 알아본 바 있다. [ &lt;a href="https://taetaetae.github.io/2016/10/08/20161008" rel="">Spring Transaction 옵션&lt;/a> ]
이번 포스팅에서는 실제로 스프링 환경에서 어떤식으로 설정해야 &lt;code>@Transactional&lt;/code> 어노테이션을 사용할수 있는지, 그리고 어떤 속성들이 있는지에 대해 알아보고자 한다.&lt;!-- more -->&lt;/p>
&lt;h2 id="설정">설정&lt;/h2>
&lt;p>기존 xml방식에서는 다음과 같이 설정을 한다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;bean&lt;/span> &lt;span class="na">id=&lt;/span>&lt;span class="s">&amp;#34;transactionManager&amp;#34;&lt;/span> &lt;span class="na">class=&lt;/span>&lt;span class="s">&amp;#34;org.springframework.jdbc.datasource.DataSourceTransactionManager&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;property&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;dataSource&amp;#34;&lt;/span> &lt;span class="na">ref=&lt;/span>&lt;span class="s">&amp;#34;dataSource&amp;#34;&lt;/span>&lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/bean&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;tx:annotation-driven&lt;/span> &lt;span class="na">transaction-manager=&lt;/span>&lt;span class="s">&amp;#34;transactionManager&amp;#34;&lt;/span> &lt;span class="na">proxy-target-class=&lt;/span>&lt;span class="s">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>혹, JavaConfig 방식으로 설정하기 위해서는 다음과 같이 설정한다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@EnableTransactionManagement&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">AppConfig&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Bean&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PlatformTransactionManager&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">transactionManager&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">URISyntaxException&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">GeneralSecurityException&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ParseException&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">IOException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DataSourceTransactionManager&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataSource&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>위와같이 설정을 해주면 트랜잭션을 설정하고자 하는 곳 어디서든 &lt;code>@Transactional&lt;/code> 어노테이션을 지정해서 적용이 가능하다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">UserService&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Transactional&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">insertUser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="주요속성">주요속성&lt;/h2>
&lt;p>&lt;code>@Transactional&lt;/code> 어노테이션의 주요속성은 다음과 같다.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>속성&lt;/th>
 &lt;th>설 명&lt;/th>
 &lt;th>사용 예&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>isolation&lt;/td>
 &lt;td>Transaction의 isolation Level. 별도로 정의하지 않으면 DB의 Isolation Level을 따름.&lt;/td>
 &lt;td>@Transactional(isolation=Isolation.DEFAULT)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>propagation&lt;/td>
 &lt;td>트랜잭션 전파규칙을 정의 , Default=REQURIED&lt;/td>
 &lt;td>@Transactional(propagation=Propagation.REQUIRED)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>readOnly&lt;/td>
 &lt;td>해당 Transaction을 읽기 전용 모드로 처리 (Default = false)&lt;/td>
 &lt;td>@Transactional(readOnly = true)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>rollbackFor&lt;/td>
 &lt;td>정의된 Exception에 대해서는 rollback을 수행&lt;/td>
 &lt;td>@Transactional(rollbackFor=Exception.class)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>noRollbackFor&lt;/td>
 &lt;td>정의된 Exception에 대해서는 rollback을 수행하지 않음.&lt;/td>
 &lt;td>@Transactional(noRollbackFor=Exception.class)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>timeout&lt;/td>
 &lt;td>지정한 시간 내에 해당 메소드 수행이 완료되지 않은 경우 rollback 수행. -1일 경우 no timeout (Default = -1)&lt;/td>
 &lt;td>@Transactional(timeout=10)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="마치며">마치며&lt;/h2>
&lt;p>자칫 잘못했다가는 원치않는 트랜잭션으로 잘못된 결과를 초래할수 있기때문에 기본값은 숙지하는게 좋을것 같다.&lt;/p></description></item><item><title>Spring Transaction 옵션</title><link>https://taetaetae.github.io/2016/10/08/20161008/</link><pubDate>Sat, 08 Oct 2016 18:04:19 +0000</pubDate><guid>https://taetaetae.github.io/2016/10/08/20161008/</guid><description>&lt;h3 id="상황">상황&lt;/h3>
&lt;p>스프링 환경에서 일반적으로 DAO 나 BO 레벨에서 다음과 같이 코딩을 하게 된다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Transactional&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isolation&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Isolation&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">READ_COMMITTED&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">propagation&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Propagation&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">REQUIRED&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">rollbackFor&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">method&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sqlMapClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;~~~~&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>무분별하게 Ctrl+C,V 신공으로 트랜잭션 어노테이션을 가져다가 사용할수도 있겠으나, 각 값들이 어떤 역활을 아는지에 대해 알고 넘어갈 필요성이 있다.&lt;/p>
&lt;h3 id="transactional">@Transactional&lt;/h3>
&lt;p>우선 해당 어노테이션을 적용하면 적용된 클래스 또는 메소드에 트랜잭션이 적용된다. 따라서 로직 흐름에 맞추어 전체적으로 트랜잭션을 적용할것인지, 아니면 특정 메소드에 적용할것인지 전략을 잘 세워야 한다.&lt;/p>
&lt;h3 id="isolation">isolation&lt;/h3>
&lt;p>격리수준이라는 옵션이다. 트랜잭션에서 일관성이 없는 데이터를 허용하도록 하는 수준을 말하는데 옵션은 다음과 같다.&lt;/p>
&lt;ol>
&lt;li>READ_UNCOMMITTED (level 0)&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>트랜잭션에 처리중인 혹은 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용&lt;/li>
&lt;li>어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 B라는 아직 완료되지 않은(Uncommitted 혹은 Dirty) 데이터 B를 읽을 수 있다.
&lt;blockquote>
&lt;p>Dirty read : 위와 같이 다른 트랜잭션에서 처리하는 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있는 현상을 dirty read 라고 하며, READ UNCOMMITTED 격리수준에서만 일어나는 현상&lt;/p>&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;ol start="2">
&lt;li>READ_COMMITTED (level 1)&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>dirty read 방지 : 트랜잭션이 커밋되어 확정된 데이터만을 읽는 것을 허용&lt;/li>
&lt;li>어떠한 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터에 접근할 수 없다.&lt;/li>
&lt;/ul>
&lt;ol start="3">
&lt;li>REPEATABLE_READ (level 2)&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능하다.&lt;/li>
&lt;li>선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제하는 것을 불허함으로써 같은 데이터를 두 번 쿼리했을 때 일관성 있는 결과를 리턴함&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>SERIALIZABLE (level 3)&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>완벽한 읽기 일관성 모드를 제공&lt;/li>
&lt;li>데이터의 일관성 및 동시성을 위해 MVCC(Multi Version Concurrency Control)을 사용하지 않음(MVCC는 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시 LOCK을 사용하지 않고 데이터의 버전을 관리해 데이터의 일관성 및 동시성을 높이는 기술)&lt;/li>
&lt;li>트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능하다.&lt;/li>
&lt;/ul>
&lt;h3 id="propagation--전파옵션">propagation ( 전파옵션)&lt;/h3>
&lt;ul>
&lt;li>REQUIRED : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 새로운 트랜잭션을 생성&lt;/li>
&lt;li>REQUIRES_NEW : 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성&lt;/li>
&lt;li>SUPPORT : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 nontransactionally로 실행&lt;/li>
&lt;li>MANDATORY : 부모 트랜잭션 내에서 실행되며 부모 트랜잭션이 없을 경우 예외가 발생&lt;/li>
&lt;li>NOT_SUPPORT : nontransactionally로 실행하며 부모 트랜잭션 내에서 실행될 경우 일시 정지&lt;/li>
&lt;li>NEVER : nontransactionally로 실행되며 부모 트랜잭션이 존재한다면 예외가 발생&lt;/li>
&lt;li>NESTED : 해당 메서드가 부모 트랜잭션에서 진행될 경우 별개로 커밋되거나 롤백될 수 있음. 둘러싼 트랜잭션이 없을 경우 REQUIRED와 동일하게 작동&lt;/li>
&lt;/ul>
&lt;h3 id="no-rollback-for---예외처리-기본값--없음">no-rollback-for - 예외처리 (기본값 : 없음)&lt;/h3>
&lt;p>특정 예외가 발생하더라도 롤백되지 않도록 설정&lt;/p>
&lt;h3 id="스프링-배치에서의-트랜잭션-내가-당했던-문제">스프링 배치에서의 트랜잭션 (내가 당했던(?) 문제)&lt;/h3>
&lt;p>스프링 배치에서는 Tasklet 에서 기본적으로 step 단위 트랜잭션을 지원하고 있다고 한다.
기본적으로 job이 하나의 tasklet 의 step 으로 실행하다보니 명시적이진 않지만 내부적으로 전체 트랜잭션으로 걸려있게 된다. 나같은 job 내 DAO delete 메소드에서 @Transactional 설정을 하고 그 DAO 메소드를 반복문에 의해 delete 하는 로직을 수행하는 부분이 있었는데 부모의 트랜잭션(tasklet에서 설정된 트랜잭션)으로 인해 dao 를 몇번 호출하던 job단위로 트렌젝션이 걸리게 되었다. (결국 트랜잭션은 반복문이 다 끝나야 적용이 된다는점.)
그러다보니 가끔 DB Query Lock이 걸렸는데 DB레벨에서 undolog를 남기는게 너무 무거워져 lock이 발생&lt;/p>
&lt;p>따라서 전파옵션을 수정해서 해당 문제를 해결하였다.&lt;/p>
&lt;pre tabindex="0">&lt;code># 기존
begin 
delete &amp;lt; for 반복문
commit

# 전파옵션 수정 (기존 REQUIRES 에서 REQUIRES_NEW 으로 수정)
for
 begin
 delete
 commit
for end 
&lt;/code>&lt;/pre></description></item></channel></rss>