spring+mybatis管理多个数据源(非分布式事务)
本文通过一个demo,介绍如何使用spring+mybatis管理多个数据源,注意,本文的事务管理并非之前博文介绍的分布式事务。
这个demo将使用两个事务管理器分别管理两个数据源。对于每一个独立的事务,只涉及一个数据源。
demo功能:实现一个能依靠两个独立的事务管理器互不干涉的管理自己的数据源的web demo。
demo将实现:
1.独立地控制两个不同的数据源的事务管理器。
测试方式:restful web api
使用工具:
spring 4.1.1.RELEASE
mybatis 3.2.7
tomcat 7
在mysql中建立两个schema,分别为dev和qa。并在里面分别建立一张名字表。
schema:dev
table:namaDev
id | nameDev
scheme:qa
table:nameQa
id | nameQa
对应的sql为
CREATE SCHEMA `qa` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
CREATE SCHEMA `dev` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ; CREATE TABLE `dev`.`nameDev` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`nameDev` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) ); CREATE TABLE `qa`.`nameQa` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`nameQa` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) );
create sql
代码分析:
本项目使用spring框架,因此首先配置相关bean
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<context:component-scan base-package="com.xy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:property-placeholder location="classpath:context/database.properties"/>
<tx:annotation-driven/> <bean id="qadataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="jdbcUrl" value="${qa.db.url}"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="user" value="${qa.db.user}"></property>
<property name="password" value="${qa.db.password}"></property>
<property name="maxPoolSize" value="20"></property>
<property name="minPoolSize" value="20"></property>
<property name="initialPoolSize" value="20"></property>
<property name="maxIdleTime" value="200"></property>
<!--<property name="numHelperThreads" value="50"></property>-->
</bean> <bean id="devdataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="jdbcUrl" value="${dev.db.url}"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="user" value="${dev.db.user}"></property>
<property name="password" value="${dev.db.password}"></property>
<property name="maxPoolSize" value="20"></property>
<property name="minPoolSize" value="20"></property>
<property name="initialPoolSize" value="20"></property>
<property name="maxIdleTime" value="200"></property>
<!--<property name="numHelperThreads" value="50"></property>-->
</bean> <bean id="qasqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="qadataSource" />
<!--<property name="mapperLocations" value="classpath*:mapper/**/*.xml" />-->
</bean> <bean id="devsqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="devdataSource" />
<!--<property name="mapperLocations" value="classpath*:mapper/**/*.xml" />-->
</bean> <bean id="qaManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="qadataSource" />
</bean> <bean id="devManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="devdataSource" />
</bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xy.dao"/>
<property name="sqlSessionFactoryBeanName" value="qasqlSessionFactory" />
</bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xy.daodev"/>
<property name="sqlSessionFactoryBeanName" value="devsqlSessionFactory" />
</bean> </beans>
其中qadataSource和devdataSource是对应两个数据库的数据源,qasqlSessionFactory和devsqlSessionFactory是mybatis的sessionfactory,两个MapperScannerConfigurer自动将不同数据源的sql语句文件与interface自动装配起来。qaManager与devManage分别管理qadataSource和devdataSource的事务,互不干涉。
Model类如下:package com.xy.model
package com.xy.model; /**
* Created by helloworld on 2015/1/30.
*/
public class NameDev {
private long id;
private String nameDev; public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getNameDev() {
return nameDev;
} public void setNameDev(String nameDev) {
this.nameDev = nameDev;
}
}
NameDev
package com.xy.model; /**
* Created by helloworld on 2015/1/30.
*/
public class NameQa {
private long id;
private String nameQa; public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getNameQa() {
return nameQa;
} public void setNameQa(String nameQa) {
this.nameQa = nameQa;
}
}
NameQa
qa数据源的mybatis mapper接口 package com.xy.dao
package com.xy.dao; import com.xy.model.NameQa; /**
* Created by helloworld on 2015/1/30.
*/
public interface NameQaMapper {
int insert(NameQa nameQa);
}
NameQaMapper
dev数据源的mybatis mapper接口 package com.xy.devdao
package com.xy.daodev; import com.xy.model.NameDev; /**
* Created by helloworld on 2015/1/30.
*/
public interface NameDevMapper {
int insert(NameDev nameDev);
}
NameDevMapper
处理事务的service
package com.xy.service; import com.xy.dao.NameQaMapper;
import com.xy.daodev.NameDevMapper;
import com.xy.model.NameDev;
import com.xy.model.NameQa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; /**
* Created by helloworld on 2015/1/30.
*/
@Service
public class NameService {
@Autowired
NameQaMapper nameQaMapper;
@Autowired
NameDevMapper nameDevMapper; @Transactional(value = "qaManager", rollbackFor = Exception.class)
public void addQa(boolean withQaException) throws Exception {
NameQa nameQa = new NameQa();
nameQa.setNameQa("hello");
nameQaMapper.insert(nameQa); if(withQaException){
throw new Exception();
}
} @Transactional(value = "devManager", rollbackFor = Exception.class)
public void addDev(boolean withDevException) throws Exception {
NameDev nameDev = new NameDev();
nameDev.setNameDev("hello");
nameDevMapper.insert(nameDev); if(withDevException){
throw new Exception();
}
} }
NameService
controller代码
package com.xy.controller; import com.xy.service.NameService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; /**
* Created by helloworld on 2014/11/22.
*/
@Controller
public class mybatisController { @Autowired
NameService nameService; @RequestMapping(value = "/addName", method = RequestMethod.POST)
ModelMap addName(@RequestParam("withDevException") boolean withDevException,
@RequestParam("witQaException") boolean witQaException ) {
try {
nameService.addDev(withDevException);
} catch (Exception e) {
e.printStackTrace();
} try {
nameService.addQa(witQaException);
} catch (Exception e) {
e.printStackTrace();
}
return new ModelMap("true");
} }
controller
将项目打成war包,命名为mybatis.war部署在tomcat上。
测试:
1.POST http://localhost:8080/mybatis/addName.json
request parameters:
withDevException=false
witQaException=false
返回:true 两个数据都添加成功
2.POST http://localhost:8080/mybatis/addName.json
request parameters:
withDevException=false
witQaException=true
返回:true 只有dev添加成功
源码下载:http://files.cnblogs.com/files/rain-in-sun/springmvc-mybatis-multidatasource.rar
spring+mybatis管理多个数据源(非分布式事务)的更多相关文章
- spring+hibernate管理多个数据源(非分布式事务)
本文通过一个demo,介绍如何使用spring+hibernate管理多个数据源,注意,本文的事务管理并非之前博文介绍的分布式事务. 这个demo将使用两个事务管理器分别管理两个数据源.对于每一个独立 ...
- springboot整合多数据源解决分布式事务
一.前言 springboot整合多数据源解决分布式事务. 1.多数据源采用分包策略 2.全局分布式事务管理:jta-atomikos. ...
- 【Rocket MQ】RocketMQ4.2.0 和 spring boot的结合使用,实现分布式事务
RocketMQ4.2.0 和 spring boot的结合使用,实现分布式事务 参考地址:https://www.jianshu.com/p/f57de40621a0
- atomikos实现多数据源支持分布式事务管理(spring、tomcat、JTA)
原文链接:http://iteye.blog.163.com/blog/static/1863080962012102945116222/ Atomikos TransactionsEssenti ...
- [教程] Spring+Mybatis环境配置多数据源
一.简要概述 在做项目的时候遇到需要从两个数据源获取数据,项目使用的Spring + Mybatis环境,看到网上有一些关于多数据源的配置,自己也整理学习一下,然后自动切换实现从不同的数据源获取数据功 ...
- SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能.也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器:第二台数据库服务器,主要进行读的操作. 目前有多种方式实现读写分离,一种 ...
- Spring Trasnaction管理(1)- 线程间事务隔离
问题导读 Spring中事务是如何实现的 Spring中各个线程间是如何进行连接.事务隔离的 Spring事务配置 Spring的事务管理应该是日常开发中总会碰到的,但是Spring具体是怎么实现线程 ...
- 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载
原文:http://www.ite/topic/122700 9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XA ...
- EF 事务(非分布式事务)
在EF 中怎么使用事务? 这个问题纠结了我好久,直到有人跟我一起讨论,我和同事一起讨论查资料. 查的好多资料都是使用 TransactionScope,用 TransactionScope 可处理分布 ...
随机推荐
- 使用 DllImport 属性
本主题说明 DllImport 属性的常见用法.第一节讨论使用 DllImport 从托管应用程序调用本机代码的优点.第二节集中讨论封送处理和 DllImport 属性的各个方面. 从托管应用程序调用 ...
- [置顶] 函数传递不定参数理解-c语言
感性认识 Typedef char *va_list;/*这个在<stdatg.h>中有定义*/ #define va_start(ap,p) (ap=(char*)(&(p)+1 ...
- 在Flash Builder或者Eclipse统计代码行数的方法
在Flash Builder或者Eclipse统计代码行数的方法如下图菜单栏--搜索--搜索文件
- 瑞丽的SQL-基于窗体的排名计算
在SQL Server中,窗体被定义为用户指定的一组行. 之所以要提出窗体这个概念,由于这种基于窗体或分区的又一次计算在实际工作应用范围比較广泛.比如.假设我们要对每一个班级中的学生按成绩进行排序,在 ...
- Codeforces Gym 100650C The Game of Efil DFS
The Game of EfilTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/v ...
- 安卓开发之探秘蓝牙隐藏API
上次讲解Android的蓝牙基本用法,这次讲得深入些,探讨下蓝牙方面的隐藏API.用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对和解除配对,但是这两项功能的函数没有在S ...
- SSL连接建立过程分析(1)
Https协议:SSL建立过程分析 web訪问的两种方式: http协议,我们普通情况下是通过它訪问web,由于它不要求太多的安全机制,使用起来也简单,非常多web网站也仅仅支持这样的方式下的訪问. ...
- iOS6 / iOS7 状态栏高度适配
问题原因:iOS7的状态栏(status bar)不再占用单独的20px,所以假设你在iOS6上的界面布局是正常的,那么到了iOS7上就会变成以下这个样子: 左边是iOS6界面 ...
- 详细的OS X Yosemite 10.10懒人版安装教程
永远记住一句话:难,是因为不会.先是要放宽心态,才更利于解决安装过程中这样那样的问题.多尝试多动脑,不要有过份的依赖.很多问题到解决以后,才发现是如此的简单,我装黑苹果是拿来使用的,所以我的目的是装好 ...
- mysql重连,连接丢失:The last packet successfully received from the server--转载
原文地址:http://nkcoder.github.io/blog/20140712/mysql-reconnect-packet-lost/ 1.1 错误信息: Caused by: com.my ...