当数据量越来越多的时候,我们就会开始考虑跨库查询,读写分离,之前对于数据库读写分离有过一定的了解,但是这里面存在着一个问题,就是A库中有a表,B库中有b表,那如果b表出现了异常,a表这个时候怎么回滚呢?当在一个数据库中直接用事务很好的处理,那如果在多个数据源中呢?其实原理是一样的。
对于一些较大的规模的应用,单个数据源已经无法支撑起庞大的用户量,需要引入多数据源,水平层面进行分库分表,降低DB的负载。另外,跨库意味着单DB的事务就失效了,所以J2EE提出了JTA,分布式事务管理,简单的说,就是分2步提交,实际它有2个容器来管理,一个资源管理器,一个事务管理,在第一个阶段中,所有参与全局事务的节点都开始准备,告诉事务管理器它们准备好提交了。第二阶段,事务管理器告诉资源管理器执行commit或者rollback,如果任何一个节点显示不能commit,那么所有的节点全部rollback,下面我们来实现分布式事务:
第一步:XA数据源定义
选定义一个抽象的父类源,这样子类可以直接继承
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close"> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/> <property name="poolSize" value="10" /> <property name="minPoolSize" value="10"/> <property name="maxPoolSize" value="30"/> <property name="borrowConnectionTimeout" value="60"/> <property name="reapTimeout" value="20"/> <property name="maxIdleTime" value="60"/> <property name="maintenanceInterval" value="60" /> <property name="loginTimeout" value="60"/> <property name="logWriter" value="60"/> <property name="testQuery"> <value>select 1value> property> bean>
master源
<bean id="masterSource" parent="abstractXADataSource"> <property name="uniqueResourceName"> <value>mastervalue> property> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" /> <property name="xaProperties"> <props> <prop key="user">库用户名prop> <prop key="password">库密码prop> <prop key="URL">master库连接prop> props> property> bean>
slave源
<bean id="slaveSource" parent="abstractXADataSource"> <property name="uniqueResourceName"> <value>slavevalue> property> <property name="xaDataSourceClassName"> <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSourcevalue> property> <property name="xaProperties"> <props> <prop key="user">库用户名prop> <prop key="password">库密码prop> <prop key="URL">slave库连接prop> props> property> bean>
基于spring的AbstractRoutingDataSource动态数据路由定义
<bean id="dataSource" class="com.icz.carcare.datasource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="master" value-ref="masterSource"/> <entry key="slave" value-ref="slaveSource"/> map> property> <property name="defaultTargetDataSource" ref="masterSource"/> bean>
mybatis中进行ORM映射
<bean id="sqlSessionFactorya" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="masterSource"/> <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" /> bean> <bean id="sqlSessionFactoryb" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="slaveSource" /> <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" /> bean>配置sessionTemplate模板
<bean id="sqlSessionTemplate" class="com.icz.carcare.sqlSessionTemplate.CustomSqlSessionTemplate"> <constructor-arg ref="sqlSessionFactorya" /> <property name="targetSqlSessionFactorys"> <map> <entry value-ref="sqlSessionFactorya" key="master"/> <entry value-ref="sqlSessionFactoryb" key="slave"/> map> property> bean>jta配置
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close"> <property name="forceShutdown"> <value>truevalue> property> bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"> <property name="transactionTimeout" value="300" /> bean> <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager"> <ref bean="atomikosTransactionManager" /> property> <property name="userTransaction"> <ref bean="atomikosUserTransaction" /> property> bean>
以上xml配置完了,现在就可以去实现跨库事务的代码编写了。
下面我们来讲讲分布式事务原理理解。
Innodb存储引擎支持XA事务,通过XA事务可以支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源参与一个全局事务中。
全局事务要求其中所参与的事务要么提交,要么全部回滚。
XA事务允许不同数据库之间的分布式事务,如:一台服务器是Mysql数据库,一台是Oracle的,又有可能还有一台是sqlserver的,只要参与全部事务中每个节点都支持XA事务。分布式事务可能在银行系统的转账中比较常见,
#bank shanghai
update user_account set money=money+100 where user='xiaozhang';
#bank beijing
update user_account set money=money-100 where user='xiaoli';
像这种情况就是,要不都提交,要不都回滚。在任何一个节点出问题都会造成严重的问题,1 xiaozhang的账号收到了钱,但是xiaoli没有扣款 2.xiaozhang的账号没有收到钱,但是xiaoli扣款了
分布式事务是由一个或者多个resource Managerd,一个事务管理器transaction manage以及一个应用程序application Program组成。
资源管理器:提供事务资源的方法,通常一个数据库就是一个资源管理器
事务管理器:协调参与全部事务各个事务,需要和参与全局事务中的资源管理员进行通信。
应用程序:定义事务的边界,指定全局事务中的操作。
在mysql分布式事务中,资源管理器就是mysql数据库,事务管理器为连接到mysql服务器的客户端。