0

我在基于 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(将路径变量转换StringFoo对象)在调用之前MyController#get()被调用,因此事务尚未开始。因此,当FooJdbcDAO被调用查询数据库时,它无法重用SessionFactory' 的连接,必须从池中检出自己的连接。

所以我的问题是:

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

  2. 如果 #1 的答案是否定的,那么有没有办法配置OpenSessionInViewFilter为在请求开始时为我们启动事务?我使用 " on_close" 作为hibernate.connection.release_mode,所以休眠会话和连接已经在请求的生命周期内保持打开状态。

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

4

1 回答 1

0
  1. 有什么方法可以在 SessionFactory 和我的 JDBC DAO 之间共享数据库连接?我正在使用 HibernateTransactionManager,从查看 Spring 的 DataSourceUtils 看来,共享事务是共享连接的唯一方法。

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

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

在您现有的包结构(在 dao 包/层中)中添加 JdbcDao 类(具有属性 jdbcTemplate 和带有 getter-setter 的数据源),扩展您的 jdbc 实现类JdbcDao。如果你已经为hibernate配置了hibernateTxManager,你就不需要配置它了。

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

--> 你这里可能错了。我认为您可能正在使用相同的连接,唯一的问题可能在于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)!

检查我的问题:在 Spring Framework 3.0 中使用 Hibernate 和 Jdbc

配置:使用您当前的休眠类添加 dao 类和服务类,如果您想使用现有配置,请不要为它们制作单独的包。否则在 xml 配置中配置 HibernateTransactionManager 并使用 @Transactional 注释。

您的代码中的错误:

@Controller
@Transactional
public class MyController {......

在服务类中使用@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
  }
}
于 2012-08-25T16:19:07.250 回答