Java ベースの webapp で Hibernate 3.2.7.GA を使用して、Spring 3.0.6 を使用しています。(サービス層ではなく)コントローラー@Transactional
でアノテーションを使用してトランザクションを宣言しています。ほとんどのビューは読み取り専用です。
JdbcTemplate
問題は、 SQL を使用して直接データベースにクエリを実行するために使用しているいくつかの DAO があり、それらがトランザクションの外部で呼び出されていることです。SessionFactory
つまり、 Hibernateの接続を再利用していないということです。それらがトランザクションの外にある理由は、次のように、コントローラーのメソッドパラメーターでコンバーターを使用しているためです。
@Controller
@Transactional
public class MyController {
@RequestMapping(value="/foo/{fooId}", method=RequestMethod.GET)
public ModelAndView get(@PathVariable("fooId") Foo foo) {
// do something with foo, and return a new ModelAndView
}
}
public class FooConverter implements Converter<String, Foo> {
@Override
public Foo convert(String fooId) {
// call FooService, which calls FooJdbcDao to look up the Foo for fooId
}
}
私のJDBC DAOは、注入されたものに依存しSimpleJdbcDaoSupport
ています:jdbcTemplate
@Repository("fooDao")
public class FooJdbcDao extends SimpleJdbcDaoSupport implements FooDao {
public Foo findById(String fooId) {
getJdbcTemplate().queryForObject("select * from foo where ...", new FooRowMapper());
// map to a Foo object, and return it
}
}
そして私のapplicationContext.xml
配線はすべて一緒です:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="FooConverter"/>
<!-- other converters -->
</set>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
FooConverter
(パス変数String
をFoo
オブジェクトに変換する) が呼び出される前MyController#get()
に呼び出されるため、トランザクションはまだ開始されていません。したがってFooJdbcDAO
、データベースを照会するために が呼び出されると、SessionFactory
の接続を再利用する方法がなく、プールから独自の接続をチェックアウトする必要があります。
だから私の質問は:
SessionFactory
と JDBC DAOの間でデータベース接続を共有する方法はありますか? 私は を使用していますがHibernateTransactionManager
、Spring を見るとDataSourceUtils
、トランザクションを共有することが接続を共有する唯一の方法であるように見えます。#1 に対する答えがno の
OpenSessionInViewFilter
場合、リクエストの開始時にトランザクションを開始するように構成する方法はありますか?on_close
に " " を使用しているhibernate.connection.release_mode
ため、Hibernate Session と Connection は、リクエストの存続期間中、すでに開いたままになっています。
これが私にとって重要な理由は、各スレッドがプールから 2 つの接続をチェックアウトしている高負荷下で問題が発生しているからです。1 つ目は休止状態によってチェックアウトされ、スレッドの全長にわたって保存され、2 つ目はJDBC DAO がトランザクション外のクエリ用に必要とするたびにチェックアウトされます。これにより、プールが空であるために 2 番目の接続をチェックアウトできない場合にデッドロックが発生しますが、最初の接続は引き続き保持されます。私の推奨する解決策は、すべての JDBC DAO を Hibernate のトランザクションに参加させることです。これによりTransactionSynchronizationManager
、1 つの接続が正しく共有されます。