一、mybatis数据源的配置文件
<!-- 配置MyBatis -->
<bean id="managerServerDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
<property name="uniqueResourceName" value="one" />
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="url">${local.jdbc.url}</prop>
<prop key="user">${local.jdbc.username}</prop>
<prop key="password">${local.jdbc.password}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="appServerDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
<property name="uniqueResourceName" value="two" />
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="url">${rmi.jdbc.url}</prop>
<prop key="user">${rmi.jdbc.username}</prop>
<prop key="password">${rmi.jdbc.password}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="multipleDataSource" class="com.dxxy.server.router.DataSourceRouter">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="managerServerDataSource" value-ref="managerServerDataSource"/>
<entry key="appServerDataSource" value-ref="appServerDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="managerServerDataSource"/>
</bean>
<!-- **坑二** -->
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="managerServerDataSource"/>
<!-- mapper文件存储在 src/main/resources/mappers 文件夹 -->
<property name="mapperLocations">
<array>
<value>classpath:mappers/managerServerMapper/*.xml</value>
</array>
</property>
</bean>
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="appServerDataSource"/>
<!-- mapper文件存储在 src/main/resources/mappers 文件夹 -->
<property name="mapperLocations">
<array>
<value>classpath:mappers/appServerMapper/*.xml</value>
</array>
</property>
</bean>
<!-- 此处很关键,需要指定不同的sqlSessionFactory,否则在事物中不会切换数据库 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"/>
<property name="basePackage" value="com.dxxy.server.dao.appServer"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
<property name="basePackage" value="com.dxxy.server.dao.managerServer"/>
</bean>
二、transaction的配置文件
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close" >
<property name="forceShutdown" value="true" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<!-- **坑一** -->
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
<property name="allowCustomIsolationLevels" value="true"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
<!-- 配置事务通知属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<!-- 定义事务传播属性 -->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="new*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="cdpRun*" propagation="REQUIRED" />
<tx:method name="cdpStop*" propagation="REQUIRED" />
<tx:method name="change*" propagation="REQUIRED" />
<tx:method name="testsubmit*" propagation="REQUIRED" />
<tx:method name="check*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* com.dxxy.server.serviceImpl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" order="2"/>
</aop:config>
以上配置有两处大坑,写这篇blog也是希望刚接触这块的朋友能够少走弯路,同时给自己留个深刻记忆。
**坑一:**transaction的配置文件的jtaTransactionManager的id命名必须为“transactionManager”,之前我写成“jtatransactionManager”时,运行会报错。大概错误内容是说(创建对象错误,transactionManager未定义之类)。把我懵B了半天,这估计是spring默认只认这个“transactionManager”为事务id吧,也没继续深究下去。毕竟spring高深之处太多了。。。(感慨中。。。)
**坑二:**mybatis数据源的配置文件的SqlSessionFactoryBean的定义,按照以往的习惯,我都会把 sqlSessionFactory1,sqlSessionFactory2写到一起,这样多省事呀。代码干净,漂亮,哈哈。。。。。
包括后面的MapperScannerConfigurer配置也会写成同一个。但是这里特别强调的是,此处必须“分而治之”。如果写到一起的话,后面测试的时候会发现,在同一个方法中对不同数据库表操作时,不会动态切换数据源,只会保留第一次切换的数据源(也就是事务开始方法执行时的数据源),当时同样懵B大半天,网上到处找答案,有人说是关于数据库切换与事务执行的时机不对,数据库切换应该在事务之前,这说的确实合理,但是如果这样子的话,如果我要在service层控制事务,那是不是要在controller层先切换事务?那又如何实现在同一个方法中对不同数据库操作呢?这也许就是使用框架的好处吧。我想atomikos已经帮我解决了相关顾虑,不需要我们去考虑数据库库切换时机问题吧(没看过源码,纯属瞎猜哈)。
不知不觉就说了一大堆了,其实只要把配置文件写好,其他的so easy,什么依赖包呀,如何用aop实现动态切换数据库之类的网上大把,不是此次博客的重点。
第一次分享博客,感觉内容少,废话多了些,请多包涵。如有兴趣一起研究java技术,可以随时联系本人qq:48828578