Как запустить устаревший код внутри управляемой весенней транзакции?

Привет, у меня есть устаревший код, который получает соединения jdbc через

DataSource.getConnection()

DataSource ограничен пространством имен Jndi.,

Предположим, что у меня есть функция, которая получает такие соединения:

foo(){
   ...
   Connection con = DataSource.getConnection()
   ...
}

И я хочу запустить этот метод foo в четко определенной транзакции spring. Как бы я это сделал?

Я использовал TransactionAwareDataSourceProxy, и он работал довольно хорошо, прежде чем я перешел на что-то вроде JPA.

Сначала я мог синхронизировать транзакцию foo с моей транзакцией spring с этой конфигурацией.

    <tx:annotation-driven transaction-manager="txManager"/>

    <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations"><list><value>classpath:/db.properties</value></list></property>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
         <constructor-arg ref="dbcpDataSource"/>
    </bean>

    <bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
        <property name="url"><value>jdbc:oracle:thin:@${jdbc.url}:1521:${jdbc.db}</value></property>
        <property name="username"><value>${jdbc.username}</value></property>
        <property name="password"><value>${jdbc.password}</value></property>
<!--    <property name="defaultAutoCommit"><value>true</value></property> -->
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

После этого я перехожу на JPA, используя LocalContainerEntityManagerFactoryBean и JpaTransactionManager.

package setup;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;


@Configuration
@EnableJpaRepositories
public class SpringContextConfiguration {


    @Bean
    public TestsSetup testSetup(){
        return new TestsSetup();
    }

    @Bean
    public TransactionAwareDataSourceProxy dataSource(){
        TransactionAwareDataSourceProxy tp = new TransactionAwareDataSourceProxy();
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        ds.setUrl("jdbc:oracle:thin:@a.a.a.a:port:some");
        ds.setUsername("user");
        ds.setPassword("paswd");
        ds.setDefaultAutoCommit(true);
        tp.setTargetDataSource(ds);
        return tp;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(dataSource);
        lef.setJpaVendorAdapter(jpaVendorAdapter);
        lef.setPackagesToScan("setup");
        return lef;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setShowSql(true);
        hibernateJpaVendorAdapter.setGenerateDdl(false);
        hibernateJpaVendorAdapter.setDatabase(Database.ORACLE);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager();
    }
}

Теперь мои устаревшие блоки кода не синхронизируются с моими управляемыми транзакциями. Как я могу преодолеть эту проблему. Любые инструменты или комментарии приветствуются.

ИЗМЕНИТЬ


person cgon    schedule 03.02.2014    source источник


Ответы (2)


Вставьте DataSource и EntityManagerFactory в bean-компонент JpaTransactionManager. См. комментарий на уровне класса @ http://docs.spring.io/spring/docs/3.2.5.RELEASE/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html для получения дополнительной информации.

person Jukka    schedule 03.02.2014

Приведенная выше конфигурация на самом деле верна, и базовые устаревшие функции вызываются внутри созданной транзакции Spring. Чего мне не хватает, так это того, что на верхнем уровне мне нужно было сбросить базовый сеанс в хранилище данных. Когда я это сделал, устаревшая транзакция начинает узнавать об измененных данных, и все работает идеально, а также транзакции можно откатить.

Я сбрасываю свой сеанс в хранилище данных следующим образом:

@Autowired
PlatformTransactionManager pt;

    TransactionDefinition td = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY);
    pt.getTransaction(td).flush();
person cgon    schedule 04.02.2014