我在基于 Java 的 webapp 中使用 Spring 3.0.6 和 Hibernate 3.2.7.GA。我在控制器@Transactional
上声明带有注释的事务(而不是在服务层中)。大多数视图都是只读的。
问题是,我有一些 DAO 用于JdbcTemplate
直接使用 SQL 查询数据库,并且它们在事务之外被调用。这意味着他们没有重用 HibernateSessionFactory
的连接。它们在事务之外的原因是我在控制器中的方法参数上使用转换器,如下所示:
@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
}
}
SimpleJdbcDaoSupport
我的JDBC DAO 依赖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 和我的 JDBC DAO 之间共享数据库连接?我正在使用HibernateTransactionManager
,并且从查看 SpringDataSourceUtils
看来,共享事务是共享连接的唯一方法。如果 #1 的答案是否定的,那么有没有办法配置
OpenSessionInViewFilter
为在请求开始时为我们启动事务?我使用 "on_close
" 作为hibernate.connection.release_mode
,所以休眠会话和连接已经在请求的生命周期内保持打开状态。
这对我来说很重要的原因是我在重负载下遇到问题,每个线程都从池中检出 2 个连接:第一个由 hibernate 检出并保存整个线程长度,第二个是每当 JDBC DAO 需要一个用于事务之外的查询时,就签出。当由于池为空而无法签出第二个连接时,这会导致死锁,但仍保留第一个连接。我首选的解决方案是让所有 JDBC DAO 参与 Hibernate 的事务,这样TransactionSynchronizationManager
才能正确共享一个连接。