設定ファイルによるトランザクション管理
Springでのトランザクション管理方法として、
が存在するが、設定ファイルを使用してトランザクション管理してみる。
使用してみる。
前回に使用したアプリケーションにトランザクションをかけてみる。
Updateをかけて、トランザクションの振る舞いを見てみる。
具体的にはContractテーブルのTimestampに現在時刻でUpdateをかける。その際4つ目のレコード更新で例外を投げる。
例外を投げるソースコード(Oobayashi.javaのcreateHouseメソッド)
public void createHouse() { List contractList = contractDao.loadAll(); Iterator<Contract> it = contractList.iterator(); int i = 0; while (it.hasNext()) { Contract contract = it.next(); contract.setTimestamp(new Date()); contractDao.update(contract); i++; if(i == 3){ throw new RuntimeException(); } } }
トランザクションをかけていない状態
3つのUpdateSQLが実行された後に、例外が投げられているのがわかる。
コンソール表示
[LOG] METHOD: buyHouse is calling. Hibernate: select this_.CONTRACT_ID as CONTRACT1_3_, this_.TIMESTAMP as TIMESTAMP3_3_, this_.WORK_ID as WORK3_3_3_, this_.COMPANY_ID as COMPANY4_3_3_, this_.USER_ID as USER5_3_3_, work2_.WORK_ID as WORK1_0_, work2_.NAME as NAME2_0_, work2_.DATE as DATE2_0_, company3_.COMPANY_ID as COMPANY1_1_, company3_.NAME as NAME0_1_, user4_.USER_ID as USER1_2_, user4_.NAME as NAME1_2_ from contract this_ left outer join work work2_ on this_.WORK_ID=work2_.WORK_ID left outer join company company3_ on this_.COMPANY_ID=company3_.COMPANY_ID left outer join user user4_ on this_.USER_ID=user4_.USER_ID log4j:WARN No appenders could be found for logger (org.springframework.context.support.FileSystemXmlApplicationContext). log4j:WARN Please initialize the log4j system properly. Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Exception in thread "main" java.lang.RuntimeException at jp.co.jjjjpppp.springtest.service.impl.Oobayashigumi.createHouse(Oobayashigumi.java:45) at jp.co.jjjjpppp.springtest.service.impl.Man.buyHouse(Man.java:18) at jp.co.jjjjpppp.springtest.service.impl.Man$$FastClassByCGLIB$$9276a0.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:693) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139) at jp.co.jjjjpppp.springtest.service.impl.LoggingAdvice.invoke(LoggingAdvice.java:17) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:628) at jp.co.jjjjpppp.springtest.service.impl.Man$$EnhancerByCGLIB$$d65a8d67.buyHouse(<generated>) at jp.co.jjjjpppp.springtest.service.impl.Main.main(Main.java:29)
DBの状態
3つだけ更新されているのがわかる。
CONTRACT_ID COMPANY_ID USER_ID WORK_ID TIMESTAMP 1 1 3 1 2008-08-06 10:15:30 2 1 7 2 2008-08-06 10:15:30 3 4 2 3 2008-08-06 10:15:30 4 4 2 4 2008-08-06 10:11:05 5 2 5 6 2008-08-06 10:11:05 6 2 6 5 2008-08-06 10:11:05
トランザクションをかけた場合
トランザクション概念図
トランザクションを設定したファイル(DatabaseBeans.xmlに追記)
<!-- トランザクションの設定 --> <!-- トランザクションマネージャの設定 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean> <!-- トランザクション属性の設定 --> <bean id="transactionAttribute" class="org.springframework.transaction.interceptor.MethodMapTransactionAttributeSource"> <property name="methodMap"> <map> <entry key="jp.co.jjjjpppp.springtest.service.impl.Man.buy*"> <value>PROPAGATION_REQUIRED, -Exception</value> </entry> </map> </property> </bean> <!-- トランザクションインターセプタの設定 --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager" /> </property> <property name="transactionAttributeSource"> <ref bean="transactionAttribute" /> </property> </bean> <!-- オートプロキシの設定 --> <bean id="transactionProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <value>man</value> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> </bean>
[ToDo]manに対してAOPのProxyとTransacsionのProxyをかけた状態で、Main.javaで「Man man = (Man) appCon.getBean("proxy");」するとClassCastExceptionがおきる。なぜ??とりあえず「Man man = (Man) appCon.getBean("man");」で回避
コンソール表示
メソッドが実行されていないのがわかる、ManのbuyHoseメソッドに対してトランザクションがかかっている状態なのでこのメソッド内で例外がおきると、更新系のSQLは1つも更新されないみたいだ。
log4j:WARN No appenders could be found for logger (org.springframework.context.support.FileSystemXmlApplicationContext). log4j:WARN Please initialize the log4j system properly. Hibernate: select this_.CONTRACT_ID as CONTRACT1_3_, this_.TIMESTAMP as TIMESTAMP3_3_, this_.WORK_ID as WORK3_3_3_, this_.COMPANY_ID as COMPANY4_3_3_, this_.USER_ID as USER5_3_3_, work2_.WORK_ID as WORK1_0_, work2_.NAME as NAME2_0_, work2_.DATE as DATE2_0_, company3_.COMPANY_ID as COMPANY1_1_, company3_.NAME as NAME0_1_, user4_.USER_ID as USER1_2_, user4_.NAME as NAME1_2_ from contract this_ left outer join work work2_ on this_.WORK_ID=work2_.WORK_ID left outer join company company3_ on this_.COMPANY_ID=company3_.COMPANY_ID left outer join user user4_ on this_.USER_ID=user4_.USER_ID Exception in thread "main" java.lang.RuntimeException at jp.co.jjjjpppp.springtest.service.impl.Oobayashigumi.createHouse(Oobayashigumi.java:45) at jp.co.jjjjpppp.springtest.service.impl.Man.buyHouse(Man.java:18) at jp.co.jjjjpppp.springtest.service.impl.Man$$FastClassByCGLIB$$9276a0.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:693) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:628) at jp.co.jjjjpppp.springtest.service.impl.Man$$EnhancerByCGLIB$$82e3e74f.buyHouse(<generated>) at jp.co.jjjjpppp.springtest.service.impl.Main.main(Main.java:29)
例外を投げずに実行
トランザクションがかかっている状態で例外を投げずに、実行してみる
コンソール表示
updateが発行されているのがわかる。
Hibernate: select this_.CONTRACT_ID as CONTRACT1_3_, this_.TIMESTAMP as TIMESTAMP3_3_, this_.WORK_ID as WORK3_3_3_, this_.COMPANY_ID as COMPANY4_3_3_, this_.USER_ID as USER5_3_3_, work2_.WORK_ID as WORK1_0_, work2_.NAME as NAME2_0_, work2_.DATE as DATE2_0_, company3_.COMPANY_ID as COMPANY1_1_, company3_.NAME as NAME0_1_, user4_.USER_ID as USER1_2_, user4_.NAME as NAME1_2_ from contract this_ left outer join work work2_ on this_.WORK_ID=work2_.WORK_ID left outer join company company3_ on this_.COMPANY_ID=company3_.COMPANY_ID left outer join user user4_ on this_.USER_ID=user4_.USER_ID Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? Hibernate: update contract set TIMESTAMP=?, WORK_ID=?, COMPANY_ID=?, USER_ID=? where CONTRACT_ID=? log4j:WARN No appenders could be found for logger (org.springframework.context.support.FileSystemXmlApplicationContext). log4j:WARN Please initialize the log4j system properly.
DBの状態
TIMESTAMPが更新されているのがわかる。
CONTRACT_ID COMPANY_ID USER_ID WORK_ID TIMESTAMP 1 1 3 1 2008-08-06 10:46:40 2 1 7 2 2008-08-06 10:46:40 3 4 2 3 2008-08-06 10:46:40 4 4 2 4 2008-08-06 10:46:40 5 2 5 6 2008-08-06 10:46:40 6 2 6 5 2008-08-06 10:46:40