我正在使用Spring 3.0.6,在基于Java的webapp中使用Hibernate 3.2.7.GA。我在控制器上声明了与@Transactional
注释的交易(而不是在服务层中)。大部分观点都是只读的。
问题是,我有一些DAO使用JdbcTemplate
直接用SQL查询数据库,并且它们在事务之外被调用。这意味着他们没有重用Hibernate SessionFactory
的连接。他们在交易之外的原因是我在控制器中的方法参数上使用转换器,如下所示:
@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的回答是否,那么有没有办法在请求开始时配置OpenSessionInViewFilter
为我们启动交易?我正在为hibernate.connection.release_mode
使用“on_close
”,因此Hibernate会话和连接已经在请求的生命周期内保持打开状态。
这对我来说很重要的原因是我在重负载下遇到问题,每个线程都从池中检出2个连接:第一个是通过休眠检出并保存到线程的整个长度,并且每当JDBC DAO需要一个用于事务之外的查询时,就会检出第二个。当第二个连接无法检出时,这会导致死锁,因为池为空,但仍保持第一个连接。我首选的解决方案是让所有JDBC DAO参与Hibernate的事务,以便TransactionSynchronizationManager
能够正确地共享一个连接。
答案 0 :(得分:0)
- 有没有办法在SessionFactory和我的JDBC DAO之间共享数据库连接?我正在使用HibernateTransactionManager,从查看Spring的DataSourceUtils看,共享事务是共享连接的唯一方式。
醇>
- &GT;那么你可以在SessionFactory和JdbcTemplate之间共享数据库连接。您需要做的是在两者之间共享相同的数据源。连接池也在两者之间共享。我在我的申请中使用它。
您需要做的是为两个事务配置HibernateTransactionManager。
在现有的包结构中添加JdbcDao类(包含属性jdbcTemplate和带有getter-setter的dataSource)(在dao包/层中),按JdbcDao
扩展jdbc实现类。如果已配置hibernateTxManager进行休眠,则无需进行配置。
问题是,我有一些DAO使用JdbcTemplate直接用SQL查询数据库,并且它们是在事务之外调用的。这意味着他们没有重用Hibernate SessionFactory的连接。
- &GT;你可能在这里错了。您可能正在使用相同的连接,我认为,问题可能只在于HibernateTransaction
配置。
检查HibernateTransactionManager javadoc:This transaction manager is appropriate for applications that use a single Hibernate SessionFactory for transactional data access, but it also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access Hibernate and services which use plain JDBC (without being aware of Hibernate)!
检查我的问题:Using Hibernate and Jdbc both in Spring Framework 3.0
配置:使用当前的hibernate类添加dao类和服务类,不要为它们创建单独的包,如果要使用现有配置。否则,在xml配置中配置HibernateTransactionManager并使用@Transactional注释。
您的代码中的错误:
@Controller
@Transactional
public class MyController {......
在服务类(best practice)中使用@Transactional
注释。
更正:
@Transactional(readOnly = true)
public class FooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}