java 一个项目里有两个数据库,怎么一个有事务,一个没有事务

kidddder
  • 551

下面这样写怎么事务控不住,在service 已经加了@Transactional 注释了
但是order里有事务,finance里没有事务(我在操作数据库的后面下了断点,去数据库看的时候已经执行了)

<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"
default-autowire="byName">


<description>Spring-配置</description>
<!-- 目录是:com.kidthief.order和com.kidthief.finance-->
<context:component-scan base-package="com.kidthief">
</context:component-scan>


<bean id="fileStorage" class="com.kidthief.util.aliyun.FileStorageOSSImpl">
    <property name="accessKeyId" value="${accessKeyId}"/>
    <property name="accessKeySecret" value="${accessKeySecret}"/>
    <property name="bucketName" value="${bucketName}"/>
    <property name="endpoint" value="${endpoint}"/>
</bean>

<bean id="ftpsFileHelper" class="com.kidthief.order.helper.FtpsFileHelper">
    <property name="host" value="${sftp.req.host}"/>
    <property name="username" value="${sftp.req.username}"/>
    <property name="password" value="${sftp.req.password}"/>
    <property name="port" value="${sftp.req.port}"/>
    <property name="dstFromPath" value="${sftp.req.dstFromPath}"/>
    <property name="localDownPath" value="${sftp.req.localDownPath}"/>
</bean>

<bean class="com.olymtech.util.spring.SpringContextHolder" lazy-init="false"/>

<bean id="propertyConfigurer" class="com.olymtech.util.diamond.DiamondPropertyPlaceholderConfigurer">
    <property name="diamondConfigKeys">
        <list>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common" />
                <property name="dataId" value="jdbc" />
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common" />
                <property name="dataId" value="dubbo" />
            </bean>
            <!--<bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common" />
                <property name="dataId" value="aws" />
            </bean>-->
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common" />
                <property name="dataId" value="api-docking" />
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common"/>
                <property name="dataId" value="mq"/>
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common"/>
                <property name="dataId" value="oss"/>
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common"/>
                <property name="dataId" value="brave"/>
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common"/>
                <property name="dataId" value="hgz"/>
            </bean>
            <bean class="com.olymtech.util.diamond.DiamondConfigKey">
                <property name="group" value="com.kidthief.common"/>
                <property name="dataId" value="public_service"/>
            </bean>
        </list>
    </property>
</bean>

<!-- MyBatis配置 -->
<bean id="mybatisSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:/config/sqlMapConfig.xml" />
<!--     自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
    <property name="typeAliasesPackage" value="com.kidthief.inventory.dao.entity" />
<!--     显式指定Mapper文件位置 -->
    <!--<property name="mapperLocations" value="classpath:/config/mappers/*Mapper.xml" />-->
    <property name="plugins">
        <array>
            <bean class="com.kidthief.util.zipkin.interceptor.MybatisZipkinSqlInfoInterceptor"/>
            <bean class="com.github.pagehelper.PageInterceptor">
                <property name="properties">
                    <value>
                        helperDialect=mysql
                    </value>
                </property>
            </bean>
        </array>
    </property>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.kidthief.order.dao.mappers;com.kidthief.order.daoext.mappers" />
    <property name="sqlSessionFactoryBeanName" value="mybatisSqlSessionFactory" />
</bean>


    <!-- 连接池配置:
    初始化连接:5 ,最大连接数量:10 , 最小空闲连接:2,最大空闲连接:10 超时等待时间以毫秒为单位:1000ms , 是否在自动回收超时连接的时候打印连接的超时错误:是 
    是否自动回收超时连接:是   超时时间(以秒数为单位):180s  -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${order-saas-jdbc.driver}" />
    <property name="url" value="${order-saas-jdbc.url}" />
    <property name="username" value="${order-saas-jdbc.username}" />
    <property name="password" value="${order-saas-jdbc.password}" />
    <property name="initialSize" value="${order-saas-jdbc.initialSize}"></property>
    <property name="maxActive" value="${order-saas-jdbc.maxActive}"></property>
    
    
    <property name="minIdle" value="${order-saas-jdbc.minIdle}"></property>
    <property name="maxIdle" value="${order-saas-jdbc.maxIdle}"></property>
    <property name="maxWait" value="${order-saas-jdbc.maxWait}"></property>
    <property name="logAbandoned" value="true" ></property>
    <property name="removeAbandoned" value="true" ></property>
    <property name="removeAbandonedTimeout" value="180" ></property>
    <property name="validationQuery" value="select now() from dual"/>
    <property name="defaultAutoCommit" value="true"></property>
    
</bean>

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

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>


<bean id="dataSource-finance" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${finance-saas-jdbc.driver}" />
    <property name="url" value="${finance-saas-jdbc.url}" />
    <property name="username" value="${finance-saas-jdbc.username}" />
    <property name="password" value="${finance-saas-jdbc.password}" />
    <property name="initialSize" value="${finance-saas-jdbc.initialSize}"></property>
    <property name="maxActive" value="${finance-saas-jdbc.maxActive}"></property>


    <property name="minIdle" value="${finance-saas-jdbc.minIdle}"></property>
    <property name="maxIdle" value="${finance-saas-jdbc.maxIdle}"></property>
    <property name="maxWait" value="${finance-saas-jdbc.maxWait}"></property>
    <property name="logAbandoned" value="true" ></property>
    <property name="removeAbandoned" value="true" ></property>
    <property name="removeAbandonedTimeout" value="180" ></property>
    <property name="validationQuery" value="select now() from dual"/>
    <property name="defaultAutoCommit" value="true"></property>

</bean>




<!-- MyBatis配置 -->
<bean id="mybatisSqlSessionFactory-finance" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource-finance" />
    <property name="configLocation" value="classpath:/config/sqlMapConfig.xml" />
    <!--     自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
    <property name="typeAliasesPackage" value="com.kidthief.finance.dao.entity;com.kidthief.finance.dto" />
    <!--     显式指定Mapper文件位置 -->
    <!--<property name="mapperLocations" value="classpath:/config/mappers/*Mapper.xml" />-->
    <property name="plugins">
        <array>
            <bean class="com.kidthief.util.zipkin.interceptor.MybatisZipkinSqlInfoInterceptor"/>
            <bean class="com.github.pagehelper.PageInterceptor">
                <property name="properties">
                    <value>
                        helperDialect=mysql
                    </value>
                </property>
            </bean>
        </array>
    </property>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.kidthief.finance.daoext.mappers;com.kidthief.finance.dao.mappers" />
    <property name="sqlSessionFactoryBeanName" value="mybatisSqlSessionFactory-finance" />
</bean>

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

<tx:annotation-driven transaction-manager="txManager-finance" proxy-target-class="true"/>



<import resource="dubboProvider.xml"/>
<import resource="dubboConsumer.xml"/>
<import resource="aliyun-mq-producer.xml"/>
<import resource="aliyun-mq-consumer.xml"/>
<import resource="zipkin-config.xml"/>
<!--<import resource="application-aws.xml"/>-->
<!--<import resource="application-quartz.xml"/>-->

</beans>

回复
阅读 202
2 个回答

可以看看atomikos

chenpeizhao
  • 3
新手上路,请多包涵

/** AOP实现多数据源事务管理

 * 线程本地变量:为什么使用栈?为了达到后进先出的效果※
 */
private static final ThreadLocal<Stack<Pair<DataSourceTransactionManager, TransactionStatus>>> THREAD_LOCAL = new ThreadLocal<>();

/**
 * 用于获取事务管理器
 */
private final ApplicationContext applicationContext;

/**
 * 事务声明
 */
private final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
{
    // 非只读模式
    def.setReadOnly(false);
    // 事务隔离级别:采用数据库的
    def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
    // 事务传播行为
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
}

/**
 * 切面
 */
@Pointcut("@annotation(com.store.generic.annotation.MultiDataSourceTransactional)")
public void pointcut() {
}

/**
 * 声明事务
 *
 * @param transactional 注解
 */
@Before("pointcut() && @annotation(transactional)")
public void before(MultiDataSourceTransactional transactional) {
    // 根据设置的事务名称按顺序声明,并放到ThreadLocal里
    String[] transactionManagerNames = transactional.transactionManagers();
    Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = new Stack<>();
    for (String transactionManagerName : transactionManagerNames) {
        DataSourceTransactionManager transactionManager = applicationContext.getBean(transactionManagerName, DataSourceTransactionManager.class);
        TransactionStatus transactionStatus = transactionManager.getTransaction(def);
        pairStack.push(new Pair(transactionManager, transactionStatus));
    }
    THREAD_LOCAL.set(pairStack);
}

/**
 * 提交事务
 */
@AfterReturning("pointcut()")
public void afterReturning() {
    // 栈顶弹出(后进先出)
    Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get();
    while (!pairStack.empty()) {
        Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop();
        pair.getKey().commit(pair.getValue());
    }
    THREAD_LOCAL.remove();
}

/**
 * 回滚事务
 */
@AfterThrowing(value = "pointcut()")
public void afterThrowing() {
    // ※栈顶弹出(后进先出)
    Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get();
    while (!pairStack.empty()) {
        Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop();
        pair.getKey().rollback(pair.getValue());
    }
    THREAD_LOCAL.remove();
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏