[ユースケース]
DbUnitとHibernateを利用したユニットテスト
- dbunitを利用してテストデータを準備
- hibernateを利用したDAOのメソッドを実行し、テストする
- トランザクションをロールバックする
(各テストメソッドは独立しているのでデータを汚してはならないから)
[問題点]
ロールバックするために、dbunitのデータ準備と、hibernateのメソッドは、同一トランザクションでなくてはならない。
=> dbunit(datasource)が、Springのトランザクション管理下になければならない。
[解決法]
TransactionAwareDatasourceProxy を利用する
[メカニズム]
まずトランザクションマネジャーがデータベースコネクションを獲得し、スレッドローカルにあるコネクションホルダーに格納する。
getConnection()メソッドが呼ばれたら、コネクションホルダーに格納されたコネクションを返すことによって、常に同じコネクションを返す。
トランザクションの途中でclose()が呼ばれても、実際にはコネクションを閉じないで、最終的にトランザクションが終了するときにコネクションを閉じる。
ConnectionHolder
トランザクションを開始されたときに、トランザクションマネジャーによってConnectionHolderのインスタンスが作成され、実際のDBコネクションを保持する。
トランザクション終了時に保持したコネクションを閉じる。
TransactionAwareDataSourceProxy
オリジナルのデータソースをラップする
Springのトランザクション管理に参加する
TransactionAwareInvocationHandler
DBコネクションのProxyクラス
プライベートインナークラスとして宣言されている
DBコネクションの一般的なメソッド(equals, closeなど)をDataSourceUtilsにデレゲートする。
[サンプル:コンフィグファイル]
<!-- | Datasource with Transaction support. --> <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> <constructor-arg ref="dbcpDataSource"/> </bean> <bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${hibernate.connection.driver_class}"/> <property name="url" value="${hibernate.connection.url}"/> <property name="username" value="${hibernate.connection.username}"/> <property name="password" value="${hibernate.connection.password}"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:hibernate.cfg.xml"/> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/> <property name="hibernateProperties" ref="hibernateProperties"/> <!--<property name="useTransactionAwareDataSource" value="true"/>--> </bean>
[サンプル:テストコード]
final IDatabaseConnection dbUnitConnection = new DatabaseConnection(this.getDataSource()); // Do some operations with dbunit // eg) // DatabaseOperation.DELETE.execute(connection, dataSet); // this doesn't close connection since method is executed under transaction DataSourceUtils.releaseConnection(dbUnitConnection.getConnection(), this.getDataSource());
[Key Spring Classes]
コメントを残す