Spring 多数据源声明式事务控制(PlatformTransactionManager )

 
首先是TransactionManager的配置:
<?xml version="1.0" encoding="gb2312"?>
<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"
	xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
	<bean id="db1Tx"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
            <ref bean="db1" />
		</property>
	</bean>

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

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

	<bean id="routingTransactionManager" class="com.mysoft.manager.impl.RoutingTransactionManager">
		<property name="targetTransactionManagers">
			<map value-type="org.springframework.transaction.PlatformTransactionManager">
				<entry key="db1" value-ref="db1Tx" />
				<entry key="db2" value-ref="db2Tx" />
				<entry key="dbc" value-ref="dbcTx" />
			</map>
		</property>
	</bean>

	<!--     配置事务回滚的场景   -->
	<tx:advice id="txAdvice" transaction-manager="routingTransactionManager">
		<tx:attributes>
            		<tx:method name="*" rollback-for="java.lang.Exception"/>
		</tx:attributes>
	</tx:advice>
	
	<!--   指定那些类的哪些方法参与事务   -->
	<aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.mysoft.manager.Manager1.publish(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.mysoft.manager.Manager2.audit(..))"/>
	</aop:config>
</beans>
 这里用到了spring的tx和aop标签, 都是spring的参考手册中的典型配置. 当调用指定的packageName.method(..)方法的时候, 将采用事务拦截, 如果在对该方法的调用过程中出现了任何异常将导致事务回滚.

接下来就是路由的问题, 其中RoutingContextHolder类内部使用一个ThreadLocal类用来指定db1, db2, db3等key值, RoutingTransactionManager类则根据当前线程中的key值取得对应的tx.
/**
* 用来存储路由到指定tx的Context
 * 
 */
@SuppressWarnings("unchecked")
public class RoutingContextHolder<T> {
    private static final ThreadLocal contextHolder = new ThreadLocal();

    public static <T> void setContext(T context) {
        Validate.notNull(context, "必须指定路由的context");
        contextHolder.set(context);
    }

    public static <T> T getContext() {
        return (T) contextHolder.get();
    }
}
 
/**
* 根据给定的路由规则来路由到合适的tx类
 * 
 * @see RoutingContextHolder
 */
public class RoutingTransactionManager implements PlatformTransactionManager {
    private Map<Object, PlatformTransactionManager> targetTransactionManagers =
            new HashMap<Object, PlatformTransactionManager>();

    /**
     * 根据给定的规则获取指定的tx
     * 
     * @return
     */
    protected PlatformTransactionManager getTargetTransactionManager() {
        Object context = RoutingContextHolder.getContext();
        Validate.notNull(context, "必须指定路由的context");
        return targetTransactionManagers.get(context);
    }

    public void setTargetTransactionManagers(Map<Object, PlatformTransactionManager> targetTransactionManagers) {
        this.targetTransactionManagers = targetTransactionManagers;
    }

    public void commit(TransactionStatus status) throws TransactionException {
        getTargetTransactionManager().commit(status);
    }

    public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
        return getTargetTransactionManager().getTransaction(definition);
    }

    public void rollback(TransactionStatus status) throws TransactionException {
        getTargetTransactionManager().rollback(status);
    }
}
 其调用代码如下:
// 指定tx的路由context
RoutingContextHolder.setContext("db1");
return manager1.publish(item);
  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Spring Boot多数据源的实现,可以通过配置多个数据源并在需要使用的时候进行切换。在Spring Boot中,可以通过使用注解来声明多个数据源,并使用特定的注解来标识当前使用的数据源。 下面是一个简单的例子: 首先在application.properties文件中配置多个数据源: ``` # 数据源1 spring.datasource.url=jdbc:mysql://localhost:3306/datasource1 spring.datasource.username=root spring.datasource.password=123456 # 数据源2 spring.datasource.datasource2.url=jdbc:mysql://localhost:3306/datasource2 spring.datasource.datasource2.username=root spring.datasource.datasource2.password=123456 ``` 然后,在需要使用数据源的地方,使用@Primary注解来标识默认的数据源,使用@Qualifier注解来指定使用哪个数据源: ``` @Service public class UserServiceImpl implements UserService { @Autowired @Qualifier("datasource1") // 指定使用datasource1数据源 private DataSource dataSource; @Autowired @Qualifier("datasource2") // 指定使用datasource2数据源 private DataSource dataSource2; @Autowired private JdbcTemplate jdbcTemplate; @Autowired @Qualifier("transactionManager") // 指定使用事务管理器 private PlatformTransactionManager transactionManager; @Override @Transactional public void addUser(User user) { // 使用默认数据源 jdbcTemplate.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge()); // 切换数据源 TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { JdbcTemplate jdbcTemplate2 = new JdbcTemplate(dataSource2); jdbcTemplate2.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge()); } }); } } ``` 在上面的例子中,我们使用了JdbcTemplate来操作数据库,并且在需要使用不同数据源的时候,使用@Qualifier注解来指定具体的数据源。同时,在需要进行事务管理的地方,使用了Spring声明式事务,并且通过注入PlatformTransactionManager来指定使用哪个事务管理器。 希望这个例子能够帮助你理解Spring Boot多数据源的实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值