springmybatis实现数据库多数据源和分布式事务
Posted 猿来在此
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springmybatis实现数据库多数据源和分布式事务相关的知识,希望对你有一定的参考价值。
数据库锁和分布式锁
数据库的读和写如果分离,在多线程操作操作时会有线程安全问题。如果只加线程锁,在分布式程序中也是不安全的。这个时候可以使用数据库的悲观锁和乐观锁,也可以使用基于redis、zk等的分布式锁解决。
多数据源
就是在一个程序服务里面,需发连接多个数据库。
动态数据源
在多数据源的基础上,要实现数据源的动态切换。
这两种复杂系统的数据库联接有相关性,也有不同应用场景的区别。如要连接两个不同的业务库,一般会使用多数据源,如要动态切换不同数据源的相同业务库,会选择使用动态数据源。
分布式事务
要支持多数据源的事务,只能用JTA事务管理(没用过 -_-||),而且应用服务器还不能是Tomcat(一直在用tomcat,不想换-_-!!),头疼了。幸亏后面还有说,有第三方的实现支持JTA事务管理,一是JOTM,一是Atomikos。只要用了其中一个,还能继续用Tomcat。因为名字短,先考虑用JOTM。到官网一看,最后更新日期是2010年。。呃。。转向Atomikos
spring 多数据源配置
spring 多数据源配置一般有两种方案(基于多数据源和动态数据源原理):
1、在spring项目启动的时候直接配置两个不同的数据源,不同的sessionFactory。在dao 层根据不同业务自行选择使用哪个数据源的session来操作。
2、配置多个不同的数据源,使用一个sessionFactory,在业务逻辑使用的时候自动切换到不同的数据源,有一个种是在拦截器里面根据不同的业务现切换到不同的datasource;有的会在业务层根据业务来自动切换。但这种方案在多线程并发的时候会出现一些问题,需要使用threadlocal等技术来实现多线程竞争切换数据源的问题。
本问主要介绍的是多数据源场景和分布式事务(Atomikos jta)的配置实现。
数据源和事务配置
--applicationContext-db.xml
<?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: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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" default-lazy-init="true">
<description>数据库配置</description>
<bean id="parentDataSource" class="com.alibaba.druid.pool.xa.DruidXADataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${druid.initialSize}"/>
<property name="minIdle" value="${druid.minIdle}"/>
<property name="maxActive" value="${druid.maxActive}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${druid.maxWait}"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="${druid.testWhileIdle}" />
<property name="testOnBorrow" value="${druid.testOnBorrow}" />
<property name="testOnReturn" value="${druid.testOnReturn}" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。-->
<property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="${druid.filters}" />
</bean>
<bean id="b2b2c" parent="parentDataSource">
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc.url.db01}"/>
<property name="username" value="${jdbc.username.db01}"/>
<property name="password" value="${jdbc.password.db01}"/>
</bean>
<bean id="es" parent="parentDataSource">
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc.url.es}"/>
<property name="username" value="${jdbc.username.es}"/>
<property name="password" value="${jdbc.password.es}"/>
</bean>
<bean id="b2b2cDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="b2b2cAtomDS"/>
<property name="xaDataSource" ref="b2b2c"/>
</bean>
<bean id="esDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="esAtomDS"/>
<property name="xaDataSource" ref="es"/>
</bean>
<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 ="jtaTxManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager"/>
<property name="userTransaction" ref="atomikosUserTransaction"/>
</bean>
<!-- 配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="jtaTxManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="servicePointCut" expression="execution(* com.leimingtech.service.es..service.*.*(..))
AND execution(* com.leimingtech.service.module..service.*.*(..))
AND execution(* com.leimingtech.extend.module..service.*.*(..))
AND execution(* com.leimingtech.gencode.service.*.*(..))" />
<aop:advisor pointcut-ref="servicePointCut" advice-ref="txAdvice" order="1" />
</aop:config>
</beans>
mybatis映射文件配置
--applicationContext-sqlmapping.xml
<?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: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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
default-lazy-init="true">
<description>Sql Mapping配置</description>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="b2b2cSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="b2b2cDataSource" />
<property name="configLocation" value="classpath:conf/sqlmap-config.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:com/leimingtech/service/module/**/dao/mapper/*Mapper.xml</value>
<value>classpath*:com/leimingtech/extend/module/**/dao/mapper/*Mapper.xml</value>
<value>classpath*:mapper/**/*Mapper.xml</value>
</list>
</property>
</bean>
<bean id="esSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="esDataSource" />
<property name="configLocation" value="classpath:conf/sqlmap-config.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:com/leimingtech/service/es/**/dao/mapper/*Mapper.xml</value>
</list>
</property>
</bean>
<!-- JDBC template -->
<bean id="jdbcTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="b2b2cSessionFactory"/>
</bean>
<!-- b2b2c db -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.sikong.**.dao.mapper;
com.leimingtech.service.module.**.dao.mapper;
com.leimingtech.extend.module.**.dao.mapper;
com.leimingtech.gencode.dao.mapper" />
<property name="annotationClass" value="com.leimingtech.core.orm.mybatis.SqlMapper"/>
<property name="sqlSessionFactoryBeanName" value="b2b2cSessionFactory"/>
</bean>
<!-- es db -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.leimingtech.service.es.**.dao.mapper;" />
<property name="annotationClass" value="com.leimingtech.core.orm.mybatis.SqlMapper"/>
<property name="sqlSessionFactoryBeanName" value="esSessionFactory"/>
</bean>
</beans>
聚焦程序猿的世界,探讨技艺,分享资源,侃谈生活……
以上是关于springmybatis实现数据库多数据源和分布式事务的主要内容,如果未能解决你的问题,请参考以下文章