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 多数据源一致性事务方案的更多相关文章

  1. spring多数据源分布式事务的分析与解决方案

    一.概述 1.业务背景 对老系统进行重构合并,导致新系统需要同时对3个数据库进行管理.由于出现跨库业务,需要实现分布式事务. 2.开发环境 spring框架版本  4.3.10.RELEASE 持久层 ...

  2. Spring框架-经典的案例和demo,一些可以直接用于生产,使用atomikos来处理多数据源的一致性事务等

    Spring Examples Demo website:http://www.ityouknow.com/ 对Spring框架的学习,包括一些经典的案例和demo,一些可以直接用于生产. sprin ...

  3. QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付

    QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付 大规模SOA系统的分 ...

  4. Spring 多数据源事务配置问题

    2009-12-22 在SpringSide 3 中,白衣提供的预先配置好的环境非常有利于用户进行快速开发,但是同时也会为扩展带来一些困难.最直接的例子就是关于在项目中使用多个数据源的问题,似乎 很难 ...

  5. Spring 多数据源 @Transactional 注解事务管理

    在 Spring,MyBatis 下两个数据源,通过 @Transactional 注解 配置简单的事务管理 spring-mybatis.xml <!--******************* ...

  6. 基于注解的Spring多数据源配置和使用(非事务)

    原文:基于注解的Spring多数据源配置和使用 1.创建DynamicDataSource类,继承AbstractRoutingDataSource package com.rps.dataSourc ...

  7. 【spring boot】SpringBoot初学(7)– 多数据源及其事务

    前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...

  8. Spring 下,关于动态数据源的事务问题的探讨

    开心一刻 毒蛇和蟒蛇在讨论谁的捕猎方式最高效. 毒蛇:我只需要咬对方一口,一段时间内它就会逐渐丧失行动能力,最后死亡. 蟒蛇冷笑:那还得等生效时间,我只需要缠住对方,就能立刻致它于死地. 毒蛇大怒:你 ...

  9. 关于Spring Boot 多数据源的事务管理

    自己的一些理解:自从用了Spring Boot 以来,这近乎零配置和"约定大于配置"的设计范式用着确实爽,其实对零配置的理解是:应该说可以是零配置可以跑一个简单的项目,因为Spri ...

随机推荐

  1. JSON.parse()和JSON.stringify()

    1.parse 用于从一个字符串中解析出json 对象.例如 var str='{"name":"cpf","age":"23&q ...

  2. C语言 · 奇偶判断

    问题描述 能被2整除的数称为偶数,不能被2整除的数称为奇数.给一个整数x,判断x是奇数还是偶数. 输入格式 输入包括一个整数x,0<=x<=100000000. 输出格式 如果x是奇数,则 ...

  3. ajax异步请求

    做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school.c ...

  4. Intellij idea添加单元测试工具

    1.idea 版本是14.0.0 ,默认带有Junit,但是不能自动生成单元测试,需要下载JunitGererator2.0插件 2.Settings -Plugins,下载 JunitGenerat ...

  5. ExtJS 4.2 业务开发(二)数据展示和查询

    本篇开始模拟一个船舶管理系统,提供查询.添加.修改船舶的功能,这里介绍其中的数据展示和查询功能. 目录 1. 数据展示 2. 数据查询 3. 在线演示 1. 数据展示 在这里我们将模拟一个船舶管理系统 ...

  6. 在Ubuntu 16.10 安装 git 并上传代码至 git.oschina.net

    1. 注册一个账号和创建项目 先在git.oschina.net上注册一个账号和新建一个project ,如project name 是"myTest". 2.安装git sudo ...

  7. Vue.js 2.0 和 React、Augular等其他框架的全方位对比

    引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那么你就来对了. 客观来说,作为核心团队成员,显然我们会 ...

  8. 声音分贝的概念,dBSPL.dBm,dBu,dBV,dBFS

    需要做个音频的PPM表,看着一堆的音频术语真是懵了,苦苦在网上扒了几天的文档,终于有了点收获,下面关于声音的分贝做个总结. 分贝 Decibel 分贝(dB)是一个对数单位(logarithmic u ...

  9. HotApp小程序服务范围资质查询器

    微信小程序提交审核需要选择资质服务范围,如果服务范围不对,审核会不通过, 开发小程序之前,最好先查询所开发小程序的资质范围,否则无法通过微信审核.   小程序的资质范围查询地址,数据同步微信官方 ht ...

  10. 网站缓存技术总结( ehcache、memcache、redis对比)

    网站技术高速发展的今天,缓存技术已经成为大型网站的一个关键技术,缓存设计好坏直接关系的一个网站访问的速度,以及购置服务器的数量,甚至影响到用户的体验. 网站缓存按照存放的地点不同,可以分为客户端缓存. ...