在Hibernate的SessionFactory和JDBC DAO之间共享连接的最佳方法是什么?

时间:2012-08-25 16:03:28

标签: java hibernate spring-mvc

我正在使用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的连接,并且必须从池中检出自己的连接。

所以我的问题是:

  1. 有没有办法在SessionFactory和我的JDBC DAO之间共享数据库连接?我正在使用HibernateTransactionManager,通过查看Spring的DataSourceUtils,共享事务似乎只是 方式来共享连接。

  2. 如果对#1的回答是,那么有没有办法在请求开始时配置OpenSessionInViewFilter为我们启动交易?我正在为hibernate.connection.release_mode使用“on_close”,因此Hibernate会话和连接已经在请求的生命周期内保持打开状态。

  3. 这对我来说很重要的原因是我在重负载下遇到问题,每个线程都从池中检出2个连接:第一个是通过休眠检出并保存到线程的整个长度,并且每当JDBC DAO需要一个用于事务之外的查询时,就会检出第二个。当第二个连接无法检出时,这会导致死锁,因为池为空,但仍保持第一个连接。我首选的解决方案是让所有JDBC DAO参与Hibernate的事务,以便TransactionSynchronizationManager能够正确地共享一个连接。

1 个答案:

答案 0 :(得分:0)

  
      
  1. 有没有办法在SessionFactory和我的JDBC DAO之间共享数据库连接?我正在使用HibernateTransactionManager,从查看Spring的DataSourceUtils看,共享事务是共享连接的唯一方式。
  2.   

- &GT;那么你可以在SessionFactory和JdbcTemplate之间共享数据库连接。您需要做的是在两者之间共享相同的数据源。连接池也在两者之间共享。我在我的申请中使用它。

您需要做的是为两个事务配置HibernateTransactionManager。

在现有的包结构中添加JdbcDao类(包含属性jdbcTemplate和带有getter-setter的dataSource)(在dao包/层中),按JdbcDao扩展jdbc实现类。如果已配置hibernateTxManager进行休眠,则无需进行配置。

  

问题是,我有一些DAO使用JdbcTemplate直接用SQL查询数据库,并且它们是在事务之外调用的。这意味着他们没有重用Hibernate SessionFactory的连接。

- &GT;你可能在这里错了。您可能正在使用相同的连接,我认为,问题可能只在于HibernateTransaction配置。

检查HibernateTransactionManager javadocThis 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
  }
}