0

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(パス変数StringFooオブジェクトに変換する) が呼び出される前MyController#get()に呼び出されるため、トランザクションはまだ開始されていません。したがってFooJdbcDAO、データベースを照会するために が呼び出されると、SessionFactoryの接続を再利用する方法がなく、プールから独自の接続をチェックアウトする必要があります。

だから私の質問は:

  1. SessionFactoryと JDBC DAOの間でデータベース接続を共有する方法はありますか? 私は を使用していますがHibernateTransactionManager、Spring を見るとDataSourceUtils、トランザクションを共有することが接続を共有する唯一の方法であるように見えます。

  2. #1 に対する答えがno のOpenSessionInViewFilter場合、リクエストの開始時にトランザクションを開始するように構成する方法はありますか? on_closeに " " を使用しているhibernate.connection.release_modeため、Hibernate Session と Connection は、リクエストの存続期間中、すでに開いたままになっています。

これが私にとって重要な理由は、各スレッドがプールから 2 つの接続をチェックアウトしている高負荷下で問題が発生しているからです。1 つ目は休止状態によってチェックアウトされ、スレッドの全長にわたって保存され、2 つ目はJDBC DAO がトランザクション外のクエリ用に必要とするたびにチェックアウトされます。これにより、プールが空であるために 2 番目の接続をチェックアウトできない場合にデッドロックが発生しますが、最初の接続は引き続き保持されます。私の推奨する解決策は、すべての JDBC DAO を Hibernate のトランザクションに参加させることです。これによりTransactionSynchronizationManager、1 つの接続が正しく共有されます。

4

1 に答える 1

0
  1. SessionFactory と JDBC DAO の間でデータベース接続を共有する方法はありますか? 私は HibernateTransactionManager を使用しています。Spring の DataSourceUtils を見ると、トランザクションを共有することが接続を共有する唯一の方法であるように見えます。

--> SessionFactory と JdbcTemplate の間でデータベース接続を共有できます。必要なことは、2 つの間で同じデータソースを共有することです。接続プーリングも 2 つの間で共有されます。私は自分のアプリケーションでそれを使用しています。

必要なことは、両方のトランザクションに対して HibernateTransactionManager を構成することです。

既存のパッケージ構造 (dao パッケージ/レイヤー) に JdbcDao クラス (プロパティ jdbcTemplate および getter-setter を使用した dataSource) を追加し、jdbc 実装クラスを で拡張しますJdbcDao。hibernate 用に hibernateTxManager を構成している場合は、構成する必要はありません。

問題は、JdbcTemplate を使用して SQL で直接データベースにクエリを実行しているいくつかの DAO があり、それらがトランザクションの外部で呼び出されていることです。つまり、Hibernate SessionFactory の接続を再利用していないということです。

--> ここで間違っているかもしれません。同じ接続を使用している可能性がありますが、構成に問題があるだけだと思い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)!

私の質問を確認してください: Spring Framework 3.0 で Hibernate と Jdbc の両方を使用する

構成 : 現在の hibernate クラスに 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 に答える