Spring 事务性池。我该使用哪一个?

发布于 2024-08-15 21:12:03 字数 4180 浏览 9 评论 0原文

我最初使用 xapool 设置 spring,但事实证明这是一个死项目,并且似乎有很多问题。

我切换到 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 与设置连接池有什么关系?

所以我被困住了。我实际上应该做什么?我不明白为什么连接池需要支持事务。所有连接都支持打开和关闭自动提交,所以我不知道这里的问题是什么。

I originally set up spring with xapool, but it turns out that's a dead project and seems to have lots of problems.

I switched to c3p0, but now I learn that the @Transactional annotations don't actually create transactions when used with c3p0. If I do the following it will insert the row into Foo even through an exception was thrown inside the method:

@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");
    }

}

This is strange because if I comment out the @Transactional annotation it will actually fail and complain about having a transaction set to rollback only:

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)

So, clearly it notices the @Transactional annotation. But, it doesn't actually set autocommit to off at the start of the method.

Here is how I have transactional stuff setup up in the applicationContext.xml. Is this correct? If not, what is this supposed to be?

<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"/>

After a bunch of searching I found a connection pool called Bitronix, but their spring setup page describes stuff about JMS which doesn't even make any sense. What does JMS have to do with setting up a connection pool?

So I'm stuck. What am I actually supposed to do? I don't understand why the connection pool needs to support transactions. All connections support turning autocommit on and off, so I have no idea what the problem is here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

趴在窗边数星星i 2024-08-22 21:12:03

经过大量的搜索和实验,我终于成功了。这是我的结果:

  • 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 有不同的 setter 名称。

对我来说,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 值放在一个位置的一种便捷方法,这样当我在一个应用程序上下文中使用多个实体管理器工厂时,我不需要重复它们。

请注意,除非您在外部 beans 元素中包含正确的设置,否则上面的 util:map 将不起作用。下面是我使用的 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(或者任何支持两阶段提交的 cpool)与 Oracle 一起工作,您需要以 SYS 用户身份运行以下授权。 (请参阅 http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/ rtrb_dsaccess2.htmlhttp://docs.codehaus.org/display/BTM/常见问题解答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)。使用物化视图或直接指向另一个数据库的单独的 EntityManager。
  • 由于某种原因,applicationContext.xml 中的 btmConfig 在设置配置值时出现问题。相反,创建一个 bitronix-default-config.properties 文件。您可以使用的配置值位于 http://docs.codehaus.org/display/BTM /配置13。该文件的其他一些配置信息位于 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

差不多就这样了。让它工作起来非常麻烦,但它现在正在工作,我很高兴。我希望这一切能够帮助那些正在经历与我相同的麻烦的人,让这一切顺利进行。

It took a lot of searching and experimentation, but I finally got things working. Here are my results:

  • enhydra xapool is a terrible connection pool. I won't enumerate the problems it caused because it doesn't matter. The latest version of that pool hasn't been updated since Dec 2006. It's a dead project.
  • I put c3p0 into my application context and got it working fairly easily. But, for some reason it just doesn't seem to support rollback even inside a single method. If I mark a method as @Transactional then do an insert into a table and then throw a RuntimeException (one that's definitely not declared in the throws list of the method because there is no throws list on the method) it will still keep the insert into that table. It will not roll back.
  • I was going to try Apache DBCP, but my searching turned up lots of complaints about it, so I didn't bother.
  • I tried Bitronix and had plenty of trouble getting it to work properly under Tomcat, but once I figured out the magic configuration it works beautifully. What follows is all the things you need to do to set it up properly.
  • I dabbled briefly with the Atomkos connection pool. It looks like it should be good, but I got Bitronix working first, so I didn't try using it much.

The configuration below works in standalone unit tests and under Tomcat. That was the major problem I had. Most of the examples I found about how to set up Spring with Bitronix assume that I'm using JBoss or some other full container.

The first bit of configuration is the part that sets up the Bitronix transaction manager.

<!-- 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" />

The major difference between that code and the examples I found is the "disableJmx" property. It throws exceptions at runtime if you don't use JMX but leave it enabled.

The next bit of configuration is the connection pool data source. Note that the connection pool classname is not the normal oracle class "oracle.jdbc.driver.OracleDriver". It's an XA data source. I don't know what the equivalent class would be in other databases.

<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>

Note also that the uniqueName needs to be different than any other data sources you have configured.

The testQuery of course needs to be specific to the database that you are using. The driver properties are specific to the database class that I'm using. OracleXADataSource for some silly reason has different setter names for OracleDriver for the same value.

The allowLocalTransactions had to be set to true for me. I found recommendations NOT to set it to true online. But, that seems to be impossible. It just won't work if it's set to false. I am not sufficiently knowledgeable about these things to know why that is.

Lastly we need to configure the entity manager factory.

<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>

Note the dataSource property refers to the id of the dataSource I declared. The persistenceXmlLocation refers to a persistence xml file that exists in the classpath somewhere. The classpath*: indicates it may be in any jar. Without the * it won't find it if it's in a jar for some reason.

I found util:map to be a handy way to put the jpaPropertyMap values in one place so that I don't need to repeat them when I use multiple entity manager factories in one application context.

Note that the util:map above won't work unless you include the proper settings in the outer beans element. Here is the header of the xml file that I use:

<?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">

Lastly, in order for Bitronix (or apparently any cpool which supports two phase commit) to work with Oracle you need to run the following grants as user SYS. (See http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rtrb_dsaccess2.html and http://docs.codehaus.org/display/BTM/FAQ and 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>;

Those grants need to be run for any user that a connection pool is set up for regardless of whether you actually do any modifying of anything. It apparently looks for those tables when a connection is established.

A few other misc issues:

  • You can't query tables which are remote synonyms in Oracle while inside a Spring @Transactional block while using Bitronix (you'll get an ORA-24777). Use materialized views or a separate EntityManager which directly points at the other DB instead.
  • For some reason the btmConfig in the applicationContext.xml has problems setting config values. Instead create a bitronix-default-config.properties file. The config values you can use are found at http://docs.codehaus.org/display/BTM/Configuration13 . Some other config info for that file is at http://docs.codehaus.org/display/BTM/JdbcConfiguration13 but I haven't used it.
  • Bitronix uses some local files to store transactional stuff. I don't know why, but I do know that if you have multiple webapps with local connection pools you will have problems because they will both try to access the same files. To fix this specify different values for bitronix.tm.journal.disk.logPart1Filename and bitronix.tm.journal.disk.logPart2Filename in the bitronix-default-config.properties for each app.
  • Bitronix javadocs are at http://www.bitronix.be/uploads/api/index.html .

That's pretty much it. It's very fiddly to get it to work, but it's working now and I'm happy. I hope that all this helps others who are going through the same troubles I did to get this all to work.

墨小沫ゞ 2024-08-22 21:12:03

当我进行连接池时,我倾向于使用我正在部署的应用程序服务器提供的连接池。那时它只是 Spring 的 JNDI 名称。

由于我不想在测试时担心应用程序服务器,因此在单元测试时我使用 DriverManagerDataSource 及其关联的事务管理器。测试时我并不关心池化或性能。我确实希望测试能够高效运行,但在这种情况下,池化并不是一个问题。

When I do connection pooling I tend to use the one provided by the app server I'm deploying on. It's just a JNDI name to Spring at that point.

Since I don't want to worry about an app server when I'm testing, I use a DriverManagerDataSource and its associated transaction manager when I'm unit testing. I'm not as concerned about pooling or performance when testing. I do want the tests to run efficiently, but pooling isn't a deal breaker in that case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文