spring分布式事务实现-程序员宅基地

技术标签: spring理解  

当数据量越来越多的时候,我们就会开始考虑跨库查询,读写分离,之前对于数据库读写分离有过一定的了解,但是这里面存在着一个问题,就是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 1</value>
    </property>
</bean>

 master源

<bean id="masterSource" parent="abstractXADataSource">
    <property name="uniqueResourceName">
        <value>master</value>
    </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>slave</value>
    </property>
    <property name="xaDataSourceClassName">
        <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
    </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">
            <!-- write 数据更新和实时数据查询-->
            <entry key="master" value-ref="masterSource"/>
            <!-- read 非实时数据查询-->
            <entry key="slave" value-ref="slaveSource"/>
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="masterSource"/> <!-- 默认使用master的数据源 -->
</bean>
 

mybatis中进行ORM映射

<bean id="sqlSessionFactorya" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="masterSource"/>
    <!-- 自动扫描sqlmaps目录, 省掉Configuration.xml里的手工配置 -->
    <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" />
</bean>

<bean id="sqlSessionFactoryb" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="slaveSource" />
    <!-- 自动扫描sqlmaps目录, 省掉Configuration.xml里的手工配置 -->
    <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" />
</bean>
配置sessionTemplate模板

<!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 -->
<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>true</value>
    </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服务器的客户端。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014209975/article/details/56013439

智能推荐

将shape文件转成geojson格式-程序员宅基地

将shape文件转成geojson格式使用ogr2ogr.exe工具E:\Program Files\PostgreSQL\9.5\bin>ogr2ogr.exe -f GEOJSON G:\fl\data\shp1\gridPoly.json G:\fl\data\shp1\gridPoly.shp

MRv1的新旧API分别与MRv2的API兼容性分析-程序员宅基地

浅析MRv1与MRv2的API兼容性1. 基本概念MRv1是Hadoop 1.X中的MapReduce实现,它由编程模型(新旧编程接口)、运行时环境(由JobTracker和TaskTracker组成)和数据处理引擎(MapTask和ReduceTask)三部分组成。该框架在扩展性、容错性(JobTracker单点)和多框架(仅支持MapReduce一种计算模型)等支持方面支持不足。关于M

python删除列表元素的所有方法_python 列表删除所有指定元素的方法-程序员宅基地

python 列表删除所有指定元素的方法如下所示:a = [1,1,1,2,3,45,1,2,1]a.remove(1)result: [1,1,2,3,45,1,2,1]while 1 in a:a.remove(1)result: [2,3,45,2]以上这篇python 列表删除所有指定元素的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。您可能感兴趣的文章..._python删除列表中所有的某个值

【深度学习-图像处理】使用pytorch搭建LeNet图像分类网络_letnet图像处理例子_Wupke的博客-程序员宅基地

【深度学习-图像处理&分类篇】pytorch&Training a Classifier官网分类demo详细复现Training a Classifier利用官方的代码加载查看数据集实例化网络完整的训练代码:train.py 文件Reference:Training a ClassifierPytorch 安装进入官网:: Pytorch.官网链接.选择版本,,方式,(pip安装)pip3 install torch==1.8.1+cu102 torchvision==0_letnet图像处理例子

linux pip命令,Linux pip 命令 command not found pip 命令详解 pip 命令未找到 pip 命令安装 - CommandNotFound ️ 坑否..._tokex的博客-程序员宅基地

显示行号|选择喜欢的代码风格默认GitHubDuneLakeSidePlateauVibrantBlueEightiesTranquilpip 命令是 Python 软件包管理器。pip 命令安装:-bash: pip command not found#Debianapt-get install python-pip#Ubuntuapt-get install python-pip#Arch L..._linux pip: command not found

【LeetCode】数独-程序员宅基地

判断一个数独是否合法,未填的空格用字符 ' . ' 表示。该数独有解并不是必要的。e.g. 如图合法数独,输入["53..7....","6..195...",".98....6.","8...6...3","4..8.3..1","7...2...6",".6....28.","...419..5","....8..79"]返回 true。我依然使用死办法解决,而且进行..._e.g. leetcode

随便推点

c语言文件如何在linux上跑,Linux中,如何编写和运行C程序-程序员宅基地

Linux正在成为开发人员的编程天堂,它是一个开放源代码和免费的操作系统。 Turbo C编译器已经是一种用于编译程序的旧方法,因此让我们的程序员转向Linux寻求新的编程环境。在本文中,我们将解释如何编写,编译和运行简单的C程序。这将成为您转入可以在Linux上编写和执行的更复杂和有用的C程序的基础。我们已经在Ubuntu 18.04 LTS系统上运行了本文中提到的步骤和命令。我们将使用Linu..._linux运行c语言里面使用linux命令

第十四周项目一 平衡二叉树-程序员宅基地

/* Copyright (c)2016,烟台大学计算机与控制工程学院 All rights reserved. 文件名称:查找.cpp 作 者: 陈朋 完成日期:2016年12月15日 版 本 号:v1.0 问题描述: 输入描述:无 程序输出:若干 */ #include stdio.h> #include mal

fgets函数测试_fgets成功判断_云雪寒的博客-程序员宅基地

函数介绍:char *fgets(char *buf, int size, FILE *fp);fgets的功能是从文件中读取一行。参数buf是一个字符串,用于保存从文件中读到的数据。参数size是打算读取内容的长度。参数fp是待读取文件的文件指针。调用fgets函数如果成功的读取到内容,函数返回buf,如果读取错误或文件已结束,返回空,即0。如果fgets返回空,可以认为是文件结束而不是发生了错误,因为发生错误的情况极少出现。函数理解:读取一次 ≠ 读取一行读取一行内容需要读取一次或以上_fgets成功判断

网页浏览器的Flash插件问题-程序员宅基地

浏览器的flash插件,firefox无力回天,改用chrome

将jar文件安装为系统服务_把jar包作为服务-程序员宅基地

将java程序安装为系统服务_把jar包作为服务

单视图几何Vanish Point(消失点/灭点)计算方法——Robert_T_Collins(罗伯特·柯林斯)算法_灭点计算_beyond951的博客-程序员宅基地

单视图几何Vanish Point(消失点/灭点)计算方法——Robert_T_Collins(罗伯特·柯林斯)算法_灭点计算