복붙노트

[SPRING] 봄 트랜잭션 cpool. 어느 것을 사용합니까?

SPRING

봄 트랜잭션 cpool. 어느 것을 사용합니까?

나는 원래 xapool로 봄을 만들었지 만 그것은 죽은 프로젝트이고 많은 문제가있는 것으로 보인다.

나는 c3p0로 전환했지만, 이제 @Transactional 주석은 c3p0과 함께 사용될 때 실제로 트랜잭션을 생성하지 않는다는 것을 알게되었습니다. 다음과 같이하면 메서드 내에서 예외가 throw 되어도 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 주석을 명확하게 알 수 있습니다. 그러나 실제로 메소드 시작시 autocommit을 off로 설정하지는 않습니다.

다음은 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는 연결 풀 설정과 어떤 관련이 있습니까?

그래서 나는 붙어있다. 내가 실제로해야할 일은 무엇인가? 연결 풀이 트랜잭션을 지원해야하는 이유를 이해할 수 없습니다. 모든 연결은 자동 커밋 기능을 켜고 끌 수 있으므로 여기에 어떤 문제가 있는지 전혀 알 수 없습니다.

해결법

  1. ==============================

    1.많은 검색과 실험이 필요했지만 마침내 일을 끝내게되었습니다. 내 결과는 다음과 같습니다.

    많은 검색과 실험이 필요했지만 마침내 일을 끝내게되었습니다. 내 결과는 다음과 같습니다.

    아래의 설정은 독립형 유닛 테스트와 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를 사용하지 않고 활성화 된 상태로두면 런타임에 예외가 발생합니다.

    구성의 다음 비트는 연결 풀 데이터 소스입니다. 연결 풀 classname은 일반적인 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로 설정해야했습니다. 나는 그것을 온라인으로 설정하지 않는 것이 좋습니다. 그러나 그것은 불가능한 것처럼 보인다. 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 * : 어떤 항아리에도있을 수 있음을 나타냅니다. 어떤 이유로 든 항아리에 있다면 *를 찾지 못할 것입니다.

    나는 util : map을 jpaPropertyMap 값을 한 곳에 두는 편리한 방법으로 하나의 어플리케이션 컨텍스트에서 여러 엔티티 관리자 팩토리를 사용할 때 반복 할 필요가 없다는 것을 발견했습니다.

    outer 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 (또는 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>;
    

    이러한 권한 부여는 실제로 어떤 내용을 수정하는지 여부에 관계없이 연결 풀이 설정된 모든 사용자에 대해 실행해야합니다. 연결이 설정되면 테이블을 찾습니다.

    몇 가지 다른 문제 :

    그것은 거의 그것입니다. 작동 시키려면 매우 혼란 스럽지만 지금은 작동 중이고 행복합니다. 이 모든 것들이 내가이 모든 일을하기 위해했던 동일한 문제를 겪고있는 다른 사람들을 도울 수 있기를 바랍니다.

  2. ==============================

    2.연결 풀링을 할 때는 배포 할 앱 서버에서 제공하는 것을 사용하는 경향이 있습니다. 이 시점에서 Spring에 대한 JNDI 이름 일뿐입니다.

    연결 풀링을 할 때는 배포 할 앱 서버에서 제공하는 것을 사용하는 경향이 있습니다. 이 시점에서 Spring에 대한 JNDI 이름 일뿐입니다.

    테스트 할 때 app 서버에 대해 걱정하고 싶지 않으므로 단위 테스트를 수행 할 때 DriverManagerDataSource 및 관련 트랜잭션 관리자를 사용합니다. 테스트 할 때 풀링이나 성능에 대해 걱정하지 않습니다. 테스트를 효율적으로 실행하고 싶지만 풀링은이 경우 거래 차단기가 아닙니다.

  3. from https://stackoverflow.com/questions/1977366/spring-transactional-cpool-which-one-do-i-use by cc-by-sa and MIT license