我想用spring自动切换数据源来实现分布式的事务
主要是想懒一下,两个数据源下有相同两个表时省着弄两个dao实体类,(内容一样但dao的名字不同才行)
上我的配置文件
<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--大数据的数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:dbType="sqlserver" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" p:url="${jdbc.shuju.url}" p:username="${jdbc.shuju.username}" p:password="${jdbc.shuju.password}" p:filters="log4j" p:useGloalDataSourceStat="true" p:validationQuery="SELECT 'x';" p:testWhileIdle="true" p:testOnBorrow="false" p:testOnReturn="false"> <property name="connectProperties"> <props> <prop key="allowMultiQueries">true</prop> </props> </property> </bean> <!--猪2.0数据源--> <bean id="dataSourceZhu2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:dbType="sqlserver" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" p:url="${jdbc.zhu.url}" p:username="${jdbc.zhu.username}" p:password="${jdbc.zhu.password}" p:filters="log4j" p:useGloalDataSourceStat="true" p:validationQuery="SELECT 'x';" p:testWhileIdle="true" p:testOnBorrow="false" p:testOnReturn="false"> <property name="connectProperties"> <props> <prop key="allowMultiQueries">true</prop> </props> </property> </bean> <!--统一权限数据源--> <bean id="dataSourceUR" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:dbType="sqlserver" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" p:url="${jdbc.role.url}" p:username="${jdbc.role.username}" p:password="${jdbc.role.password}" p:filters="log4j" p:useGloalDataSourceStat="true" p:validationQuery="SELECT 'x';" p:testWhileIdle="true" p:testOnBorrow="false" p:testOnReturn="false"> <property name="connectProperties"> <props> <prop key="allowMultiQueries">true</prop> </props> </property> </bean> <!--数据源交给Spring控制--> <bean id="multipleDataSource" class="com.nxin.common.autodatasource.MultipleDataSource"> <property name="defaultTargetDataSource" ref="dataSource"/> <property name="targetDataSources"> <map> <entry key="zhu2" value-ref="dataSourceZhu2"/> <entry key="role" value-ref="dataSourceUR"/> <entry key="default" value-ref="dataSource"/> </map> </property> </bean> <!-- 配置数据源切换实现类--> <bean id="dataSourceContextHolder" class="com.nxin.common.autodatasource.DataSourceContextHolder" /> <!-- 切面还原默认数据源(执行完service层后切回)--> <aop:config> <aop:aspect id="dataSourceHolderAdviceAspect" ref="dataSourceContextHolder"> <aop:after-returning method="setDefaultDbType" pointcut="execution(public * com.nxin.*.*.service..*.*(..))" /> <aop:after-throwing method="clearDbType" pointcut="execution(public * com.nxin.*.*.service..*.*(..))" /> </aop:aspect> </aop:config> <!--mybatis的sessionFactory和Mapper配置--> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" p:dataSource-ref="multipleDataSource" p:typeAliasesPackage="com.nxin.shuju.user.bo,com.nxin.shuju.application.bo" p:mapperLocations="classpath*:/config/dao/*.xml"/> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" p:basePackage="com.nxin.shuju.*.dao"/> <!--mybatis的事务配置--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="multipleDataSource"/> <tx:advice id="advice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException"/> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="find*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="get*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="select*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointcut" expression="execution(public * com.nxin.*.*.service..*.*(..))" /> <!--把事务控制在Service层--> <aop:advisor pointcut-ref="pointcut" advice-ref="advice"/> </aop:config> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" p:transactionManager-ref="transactionManager"/> <bean id="ucTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="multipleDataSource"/> </beans>
但这样问题来了,我把事务处理控制在service层,所以就要在control层切换到指定数据源,例如:
DataSourceContextHolder.setDbType("role");
我曾尝试在service层被事务拦截的方法中切数据源,但根本就无效,执行会报错,找不到对应数据库表
但是不被事务拦截的方法中是可以自由切换数据源,程序执行没有问题。
这tm是为毛啊???
后来想想,既然被事务拦截,一定是事务开启就要指定sessionFactory的数据源唯一连接所以在进入service处理之前就要指定好数据源,
向上面我的做法!!!放在control层
所以想想,这种切数据源的做法是不适合分布式事务的!不过要只是切库查询应该还是没有太大问题的!
要分布式事务,还得用老老实实用jta阿!!!
不过这里我用的
DataSourceTransactionManager
不知道要是用JtaTransactionManager是不是就好用尼!!!
我说的意思是自动切数据源
multipleDataSource+JtaTransactionManager
有这样弄过的吗? 告诉告诉本懒人!!!