3

私はもともと xapool で春をセットアップしましたが、それは死んでいるプロジェクトであり、多くの問題があるようです。

c3p0 に切り替えましたが、@Transactional アノテーションを c3p0 で使用すると、実際にはトランザクションが作成されないことがわかりました。次のようにすると、メソッド内で例外がスローされても、行が Foo に挿入されます。

@Service
public class FooTst
{
    @PersistenceContext(unitName="accessControlDb") private EntityManager em;

    @Transactional
    public void insertFoo() {
        em.createNativeQuery("INSERT INTO Foo (id) VALUES (:id)")
            .setParameter("id", System.currentTimeMillis() % Integer.MAX_VALUE )
            .executeUpdate();

        throw new RuntimeException("Foo");
    }

}

@Transactional アノテーションをコメントアウトすると、実際には失敗し、トランザクションがロールバックのみに設定されていると不平を言うため、これは奇妙です。

java.lang.IllegalStateException: Cannot get Transaction for setRollbackOnly
    at org.objectweb.jotm.Current.setRollbackOnly(Current.java:568)
    at org.hibernate.ejb.AbstractEntityManagerImpl.markAsRollback(AbstractEntityManagerImpl.java:421)
    at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:576)
    at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:48)
    at com.ipass.rbac.svc.FooTst.insertFoo(FooTst.java:21)
    at com.ipass.rbac.svc.SingleTst.testHasPriv(SingleTst.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233)
    at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)
    at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

したがって、明らかに @Transactional アノテーションに気づきます。ただし、メソッドの開始時に実際に自動コミットをオフに設定するわけではありません。

ここでは、applicationContext.xml でトランザクションをセットアップする方法を示します。これは正しいです?そうでない場合、これは何ですか?

<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="jotm"/>
    <property name="userTransaction" ref="jotm"/>
    <property name="allowCustomIsolationLevels" value="true"/>
</bean>
<tx:annotation-driven  transaction-manager="txManager" proxy-target-class="false"/>

一連の検索の後、Bitronix と呼ばれる接続プールを見つけましたが、Spring セットアップ ページには意味をなさない JMS に関する説明が記載されています。JMS は接続プールの設定とどのような関係がありますか?

だから私は立ち往生しています。私は実際に何をすべきですか?接続プールがトランザクションをサポートする必要がある理由がわかりません。すべての接続は自動コミットのオンとオフをサポートしているため、ここで何が問題なのかわかりません。

4

2 に答える 2

2

多くの検索と実験が必要でしたが、ようやく機能するようになりました。ここに私の結果があります:

  • enhydra xapool はひどい接続プールです。問題ではないので、それが引き起こした問題を列挙しません。そのプールの最新バージョンは 2006 年 12 月以来更新されていません。これはデッド プロジェクトです。
  • c3p0 をアプリケーション コンテキストに入れると、かなり簡単に動作するようになりました。しかし、何らかの理由で、単一のメソッド内でもロールバックをサポートしていないようです。メソッドを@Transactionalとしてマークし、テーブルに挿入してからRuntimeException(メソッドにスローリストがないため、メソッドのスローリストで宣言されていないもの)をスローすると、挿入が保持されますそのテーブル。ロールバックしません。
  • Apache DBCP を試してみようと思ったのですが、調べてみるとそれに関する苦情がたくさん出てきたので、気にしませんでした。
  • 私は Bitronix を試してみましたが、Tomcat の下で適切に動作させるのにかなり苦労しましたが、魔法の設定を理解すると、見事に動作します。以下は、適切に設定するために必要なすべてのことです。
  • Atomkos 接続プールを簡単に試してみました。良さそうですが、Bitronixが先に動いたのであまり使ってみませんでした。

以下の構成は、スタンドアロンの単体テストおよび Tomcat の下で機能します。それが私が抱えていた大きな問題でした。Bitronix で Spring をセットアップする方法について私が見つけた例のほとんどは、JBoss またはその他の完全なコンテナーを使用していることを前提としています。

構成の最初のビットは、Bitronix トランザクション マネージャーを設定する部分です。

<!-- Bitronix transaction manager -->
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
    <property name="disableJmx" value="true" />
</bean>
<bean id="btmManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="btmManager" />
    <property name="userTransaction" ref="btmManager" />
    <property name="allowCustomIsolationLevels" value="true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

そのコードと私が見つけた例の主な違いは、「disableJmx」プロパティです。JMX を使用せずに有効にしておくと、実行時に例外がスローされます。

構成の次の部分は、接続プール データ ソースです。接続プールのクラス名は、通常の Oracle クラス「oracle.jdbc.driver.OracleDriver」ではないことに注意してください。これは XA データ ソースです。他のデータベースで同等のクラスが何であるかはわかりません。

<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
    <property name="uniqueName" value="dataSource-BTM" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="4" />
    <property name="testQuery" value="SELECT 1 FROM dual" />
    <property name="driverProperties"><props>
        <prop key="URL">${jdbc.url}</prop>
        <prop key="user">${jdbc.username}</prop>
        <prop key="password">${jdbc.password}</prop>
    </props></property>
    <property name="className" value="oracle.jdbc.xa.client.OracleXADataSource" />
    <property name="allowLocalTransactions" value="true" />
</bean>

uniqueName は、構成した他のデータ ソースとは異なる必要があることにも注意してください。

もちろん、testQuery は、使用しているデータベースに固有のものである必要があります。ドライバーのプロパティは、使用しているデータベース クラスに固有のものです。OracleXADataSource は、何らかの愚かな理由で、同じ値に対して OracleDriver のセッター名が異なります。

allowLocalTransactions を true に設定する必要がありました。オンラインでtrueに設定しないという推奨事項を見つけました。でも、それは無理そうです。false に設定すると機能しません。私はこれらのことについて十分に知識がなく、その理由を知ることができません。

最後に、エンティティ マネージャー ファクトリを構成する必要があります。

<util:map id="jpa_property_map">
    <entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup"/>
    <entry key="hibernate.current_session_context_class" value="jta"/>
</util:map>

<bean id="dataSource-emf" name="accessControlDb" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceXmlLocation" value="classpath*:META-INF/foo-persistence.xml" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true"/>
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
        </bean>
    </property>
    <property name="jpaPropertyMap" ref="jpa_property_map"/>
    <property name="jpaDialect"><bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/></property>
</bean>

dataSource プロパティは、宣言した dataSource の ID を参照していることに注意してください。persistenceXmlLocation は、クラスパスのどこかに存在する永続化 xml ファイルを参照します。classpath*: は、任意の jar にある可能性があることを示します。* がないと、何らかの理由で瓶に入っている場合に見つかりません。

util:map は jpaPropertyMap の値を 1 つの場所に配置する便利な方法であることがわかりました。これにより、1 つのアプリケーション コンテキストで複数のエンティティ マネージャー ファクトリを使用する場合にそれらを繰り返す必要がなくなります。

上記の util:map は、外側の Bean 要素に適切な設定を含めない限り機能しないことに注意してください。私が使用するxmlファイルのヘッダーは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

最後に、Bitronix (または明らかに 2 フェーズ コミットをサポートする任意の cpool) が Oracle と連携するには、ユーザー SYS として次の許可を実行する必要があります。( http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rtrb_dsaccess2.htmlおよびhttp:/ /docs.codehaus.org/display/BTM/FAQおよびhttp://docs.codehaus.org/display/BTM/JdbcXaSupportEvaluation#JdbcXaSupportEvaluation-Oracle )

grant select on pending_trans$ to <someUsername>;
grant select on dba_2pc_pending to <someUsername>;
grant select on dba_pending_transactions to <someUsername>;
grant execute on dbms_system to <someUsername>;

これらの許可は、実際に何かを変更するかどうかに関係なく、接続プールが設定されているすべてのユーザーに対して実行する必要があります。接続が確立されると、明らかにそれらのテーブルを探します。

その他のいくつかの問題:

  • Bitronix を使用している場合、Spring @Transactional ブロッ​​ク内で Oracle のリモート シノニムであるテーブルをクエリすることはできません (ORA-24777 が発生します)。代わりに、マテリアライズド ビューまたは他の DB を直接指す別の EntityManager を使用します。
  • 何らかの理由で、applicationContext.xml の btmConfig に設定値の設定に問題があります。代わりに bitronix-default-config.properties ファイルを作成してください。使用できる設定値はhttp://docs.codehaus.org/display/BTM/Configuration13にあります。そのファイルのその他の構成情報はhttp://docs.codehaus.org/display/BTM/JdbcConfiguration13にありますが、私は使用していません。
  • Bitronix は、いくつかのローカル ファイルを使用してトランザクション データを保存します。理由はわかりませんが、ローカル接続プールを持つ複数の Web アプリケーションがある場合、両方が同じファイルにアクセスしようとするため、問題が発生することはわかっています。これを修正するには、各アプリの bitronix-default-config.properties で bitronix.tm.journal.disk.logPart1Filename と bitronix.tm.journal.disk.logPart2Filename に異なる値を指定します。
  • Bitronix javadoc はhttp://www.bitronix.be/uploads/api/index.htmlにあります。

それだけです。それを機能させるのは非常に手間がかかりますが、現在は機能しており、満足しています。このすべてが、私がこれをすべて機能させるために行ったのと同じトラブルを経験している他の人に役立つことを願っています.

于 2010-01-04T21:52:24.897 に答える
0

接続プールを行うときは、展開しているアプリサーバーによって提供されるものを使用する傾向があります。その時点でのSpringのJNDI名にすぎません。

テストするときはアプリサーバーについて心配したくないので、単体テストするときはDriverManagerDataSourceとそれに関連するトランザクションマネージャーを使用します。テストするときは、プーリングやパフォーマンスについてはそれほど心配していません。テストを効率的に実行したいのですが、その場合、プーリングは大きな問題にはなりません。

于 2009-12-29T23:45:49.780 に答える