spring 多数据源一致性事务方案
spring 多数据源配置
spring 多数据源配置一般有两种方案:
1、在spring项目启动的时候直接配置两个不同的数据源,不同的sessionFactory。在dao 层根据不同业务自行选择使用哪个数据源的session来操作。
2、配置多个不同的数据源,使用一个sessionFactory,在业务逻辑使用的时候自动切换到不同的数据源,有一个种是在拦截器里面根据不同的业务现切换到不同的datasource;有的会在业务层根据业务来自动切换。但这种方案在多线程并发的时候会出现一些问题,需要使用threadlocal等技术来实现多线程竞争切换数据源的问题。
【本文暂时只讨论第一种方案】
spring多事务配置主要体现在db配置这块,配置不同的数据源和不同的session
1、一下贴出 spring-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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <bean id="test1DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="${database.test1.driverClassName}" />
<property name="url" value="${database.test1.url}" />
<property name="username" value="${database.test1.username}" />
<property name="password" value="${database.test1.password}" />
</bean> <bean id="test2DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="${database.test2.driverClassName}" />
<property name="url" value="${database.test2.url}" />
<property name="username" value="${database.test2.username}" />
<property name="password" value="${database.test2.password}" />
</bean> <bean id="test1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="test1DataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
</bean> <bean id="test2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="test2DataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
</bean> <bean id="test1TxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="test1DataSource"></property>
</bean>
<bean id="test2TxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="test2DataSource"></property>
</bean> <tx:annotation-driven transaction-manager="test2TxManager" />
<tx:annotation-driven transaction-manager="test1TxManager" /> </beans>
2、dao层做了一个小的封装,将不同的SqlSessionFactory 注入到 SessionFactory,通过BaseDao来做简单的封装,封装不同库的基本增删改。dao实现层都集成于Basedao 这样的话,实现可以根据自己需要来选择不同的库来操作不同的内容。
session工厂
package com.neo.dao;
import com.neo.entity.Entity;
public class BaseDao extends SessionFactory{
public void test1Update(Entity entity) {
this.getTest1Session().update(entity.getClass().getSimpleName()+".update", entity);
}
public void test2Update(Entity entity) {
this.getTest2Session().update(entity.getClass().getSimpleName()+".update", entity);
}
}
BaseDao
package com.neo.dao;
import com.neo.entity.Entity;
public class BaseDao extends SessionFactory{
public void test1Update(Entity entity) {
this.getTest1Session().update(entity.getClass().getSimpleName()+".update", entity);
}
public void test2Update(Entity entity) {
this.getTest2Session().update(entity.getClass().getSimpleName()+".update", entity);
}
}
以上的配置在多数据源连接,正常的增删改都是没有问题的,但是遇到分布式的事务是就出问题:
测试代码:
package com.neo.service.impl; import javax.annotation.Resource; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.neo.dao.UserDao;
import com.neo.dao.UserInformationsDao;
import com.neo.entity.UserEntity;
import com.neo.entity.UserInformationsEntity;
import com.neo.service.UserService; @Service
public class UserServiceImpl implements UserService { @Resource UserDao userDao;
@Resource UserInformationsDao userInformationsDao; @Override
@Transactional
public void updateUserinfo() { UserEntity user=new UserEntity();
user.setId(1);
user.setUserName("李四4"); UserInformationsEntity userInfo=new UserInformationsEntity();
userInfo.setUserId(1);
userInfo.setAddress("陕西4"); userDao.updateUser(user);
userInformationsDao.updateUserInformations(userInfo); if(true){
throw new RuntimeException("test tx ");
}
} }
在service添加事务后,更新完毕抛出异常,test2更新进行了回滚,test1 数据更新没有回滚。
解决方案添加分布式的事务,Atomikos和spring结合来处理。
Atomikos多数据源的配置
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <bean id="test1DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="test1"/>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="url">${database.test1.url}</prop>
<prop key="user">${database.test1.username}</prop>
<prop key="password">${database.test1.password}</prop>
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="testQuery" value="select 1" />
<property name="maintenanceInterval" value="60" />
</bean> <bean id="test2DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="test2"/>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="url">${database.test2.url}</prop>
<prop key="user">${database.test2.username}</prop>
<prop key="password">${database.test2.password}</prop>
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="testQuery" value="select 1" />
<property name="maintenanceInterval" value="60" />
</bean> <bean id="test1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="test1DataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
</bean> <bean id="test2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="test2DataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
</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="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager"/>
<property name="userTransaction" ref="atomikosUserTransaction"/>
</bean> <tx:annotation-driven/> </beans>
所有代码请参考这里:
https://github.com/ityouknow/spring-examples
spring 多数据源一致性事务方案的更多相关文章
- spring多数据源分布式事务的分析与解决方案
一.概述 1.业务背景 对老系统进行重构合并,导致新系统需要同时对3个数据库进行管理.由于出现跨库业务,需要实现分布式事务. 2.开发环境 spring框架版本 4.3.10.RELEASE 持久层 ...
- Spring框架-经典的案例和demo,一些可以直接用于生产,使用atomikos来处理多数据源的一致性事务等
Spring Examples Demo website:http://www.ityouknow.com/ 对Spring框架的学习,包括一些经典的案例和demo,一些可以直接用于生产. sprin ...
- QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付
QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付 大规模SOA系统的分 ...
- Spring 多数据源事务配置问题
2009-12-22 在SpringSide 3 中,白衣提供的预先配置好的环境非常有利于用户进行快速开发,但是同时也会为扩展带来一些困难.最直接的例子就是关于在项目中使用多个数据源的问题,似乎 很难 ...
- Spring 多数据源 @Transactional 注解事务管理
在 Spring,MyBatis 下两个数据源,通过 @Transactional 注解 配置简单的事务管理 spring-mybatis.xml <!--******************* ...
- 基于注解的Spring多数据源配置和使用(非事务)
原文:基于注解的Spring多数据源配置和使用 1.创建DynamicDataSource类,继承AbstractRoutingDataSource package com.rps.dataSourc ...
- 【spring boot】SpringBoot初学(7)– 多数据源及其事务
前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...
- Spring 下,关于动态数据源的事务问题的探讨
开心一刻 毒蛇和蟒蛇在讨论谁的捕猎方式最高效. 毒蛇:我只需要咬对方一口,一段时间内它就会逐渐丧失行动能力,最后死亡. 蟒蛇冷笑:那还得等生效时间,我只需要缠住对方,就能立刻致它于死地. 毒蛇大怒:你 ...
- 关于Spring Boot 多数据源的事务管理
自己的一些理解:自从用了Spring Boot 以来,这近乎零配置和"约定大于配置"的设计范式用着确实爽,其实对零配置的理解是:应该说可以是零配置可以跑一个简单的项目,因为Spri ...
随机推荐
- JSON.parse()和JSON.stringify()
1.parse 用于从一个字符串中解析出json 对象.例如 var str='{"name":"cpf","age":"23&q ...
- C语言 · 奇偶判断
问题描述 能被2整除的数称为偶数,不能被2整除的数称为奇数.给一个整数x,判断x是奇数还是偶数. 输入格式 输入包括一个整数x,0<=x<=100000000. 输出格式 如果x是奇数,则 ...
- ajax异步请求
做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school.c ...
- Intellij idea添加单元测试工具
1.idea 版本是14.0.0 ,默认带有Junit,但是不能自动生成单元测试,需要下载JunitGererator2.0插件 2.Settings -Plugins,下载 JunitGenerat ...
- ExtJS 4.2 业务开发(二)数据展示和查询
本篇开始模拟一个船舶管理系统,提供查询.添加.修改船舶的功能,这里介绍其中的数据展示和查询功能. 目录 1. 数据展示 2. 数据查询 3. 在线演示 1. 数据展示 在这里我们将模拟一个船舶管理系统 ...
- 在Ubuntu 16.10 安装 git 并上传代码至 git.oschina.net
1. 注册一个账号和创建项目 先在git.oschina.net上注册一个账号和新建一个project ,如project name 是"myTest". 2.安装git sudo ...
- Vue.js 2.0 和 React、Augular等其他框架的全方位对比
引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那么你就来对了. 客观来说,作为核心团队成员,显然我们会 ...
- 声音分贝的概念,dBSPL.dBm,dBu,dBV,dBFS
需要做个音频的PPM表,看着一堆的音频术语真是懵了,苦苦在网上扒了几天的文档,终于有了点收获,下面关于声音的分贝做个总结. 分贝 Decibel 分贝(dB)是一个对数单位(logarithmic u ...
- HotApp小程序服务范围资质查询器
微信小程序提交审核需要选择资质服务范围,如果服务范围不对,审核会不通过, 开发小程序之前,最好先查询所开发小程序的资质范围,否则无法通过微信审核. 小程序的资质范围查询地址,数据同步微信官方 ht ...
- 网站缓存技术总结( ehcache、memcache、redis对比)
网站技术高速发展的今天,缓存技术已经成为大型网站的一个关键技术,缓存设计好坏直接关系的一个网站访问的速度,以及购置服务器的数量,甚至影响到用户的体验. 网站缓存按照存放的地点不同,可以分为客户端缓存. ...