spring + mybatis + 多数据源整合事务

1、核心思想,spring提供了一个DataSource的子类,该类支持多个数据源

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

该类的源码如下:

org.springframework.jdbc.datasource.lookup;

java.sql.Connection;
java.sql.SQLException;
java.util.HashMap;
java.util.Iterator;
java.util.Map;
java.util.Map.Entry;
javax.sql.DataSource;
org.springframework.beans.factory.InitializingBean;
org.springframework.jdbc.datasource.AbstractDataSource;
org.springframework.jdbc.datasource.lookup.DataSourceLookup;
org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
org.springframework.util.Assert;

AbstractRoutingDataSource AbstractDataSource InitializingBean {

    // 注意这里,这里使用Map存放多个数据源
    Map<Object, Object> targetDataSources;
 
    ... // 篇幅有限,省略其他代码,有兴趣的同学可以自行研究,还是支持蛮多功能的,比如JNDI等数据源方式     

    // 注意这个暴露的方法,spring在从数据源中获取数据库连接时,通过这个方法确定数据源
    DataSource determineTargetDataSource() {
        Assert.notNull(.resolvedDataSources, );
        Object lookupKey = .determineCurrentLookupKey();
        DataSource dataSource = (DataSource).resolvedDataSources.get(lookupKey);
        (dataSource == && (.lenientFallback || lookupKey == )) {
            dataSource = .resolvedDefaultDataSource;
        }

        (dataSource == ) {
            IllegalStateException(+ lookupKey + );
        } {
            dataSource;
        }
    }

    // 对外暴露的决定数据源的方法,通过外部设置数据源的key值,
    // spring自行从已存储的数据源中查找指定数据源
    Object determineCurrentLookupKey();
}

通过分析源码,可以知道我们只需要实现如何动态设置切换数据源的方式即可,可以考虑使用注解的方式在指定的位置添加数据源注解,利用AOP动态指定数据源。

自定义的数据源如下:

com.yao.yz.yaowangdrug.dataSource;

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

DynamicDataSource AbstractRoutingDataSource{

    Object determineCurrentLookupKey() {
        DataSourceHolder.();
    }
}

2、自定义注解,本章节不做过多解释,对于注解有兴趣的同学请自行研究,废话一句:程序员以实际应用为主,研究行的内容请自行学习

com.yao.yz.yaowangdrug.dataSource;

java.lang.annotation.*;

(RetentionPolicy.)
(ElementType.)
@{
    String value();
}

3、定义一个数据源切换功能组件,其中数据源存放的方式采用ThreadLocal的形式,我是单独把存放做成一个额外的组件,这个是可以自行决定的,代码如下:

com.yao.yz.yaowangdrug.dataSource;

DataSourceHolder {

    ThreadLocal<String> = InheritableThreadLocal<String>();

    setDataSourceKey(String dataSource) {
        .set(dataSource);
    }

    Object getDataSourceKey() {
       .get();
    }

}
com.yao.yz.yaowangdrug.dataSource;

org.apache.log4j.Logger;
org.aspectj.lang.JoinPoint;
org.aspectj.lang.reflect.MethodSignature;

java.lang.reflect.Method;

DynamicAspect {

    Logger = Logger.(DynamicAspect.);

    switchDataSource(JoinPoint point) NoSuchMethodException
    {
        Object target = point.getTarget();
        String method = point.getSignature().getName();

        Class<?>[] classz = target.getClass().getInterfaces();

        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        Method m = classz[].getMethod(method, parameterTypes);
        (m != && m.isAnnotationPresent(.)) {
            data = m
                    .getAnnotation(.);
            DataSourceHolder.(data.value());
        }
        .info(+ DataSourceHolder.());
    }

}

4、在spring配置文件添加多个数据源,并将多个数据源统一纳入自定义数据源的管理,具体的配置信息如下:

<!--装载配置文件,将数据源的配置做成配置文件,方便管理,有兴趣的同学自行参考--><bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">   <property name="location" value="Config.properties"/></bean>

<!--数据源1--><bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">       <property name="driverClass" value="com.mysql.jdbc.Driver" />       <property name="jdbcUrl" value="${dataSource1.jdbc.url}" />       <property name="user" value="${dataSource1.jdbc.username}" />       <property name="password" value="${dataSource1.jdbc.password}" />       <property name="minPoolSize" value="${dataSource1.jdbc.minPoolSize}" />       <property name="maxPoolSize" value="${dataSource1.jdbc.maxPoolSize}" />   </bean>

<!--数据源2--><bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">   <property name="driverClass" value="com.mysql.jdbc.Driver" />   <property name="jdbcUrl" value="${dataSource2.jdbc.url}" />   <property name="user" value="${dataSource2.jdbc.username}" />   <property name="password" value="${dataSource2.jdbc.password}" />   <property name="minPoolSize" value="${dataSource2.jdbc.minPoolSize}" />   <property name="maxPoolSize" value="${dataSource2.jdbc.maxPoolSize}" /></bean>

<!--自定义数据源,将所有的数据源纳入自定义数据源管理--><bean id="dataSource" class="com.yao.yz.yaowangdrug.dataSource.DynamicDataSource">   <property name="targetDataSources">      <map>          <!-- 对应spring提供的AbstractRoutingDataSource的Map -->         <entry key="dataSource1" value-ref="dataSource1"/>         <entry key="dataSource2" value-ref="dataSource2"/>      </map>   </property>   <property name="defaultTargetDataSource" ref="dataSource1"/></bean>

5、配置数据源切换的AOP,代码如下:

<!--动态决定数据源--><bean id="dataSourceSwitchAspect" class="com.yao.yz.yaowangdrug.dataSource.DynamicAspect"/><aop:config>   <aop:aspect id="dynamicAspect" ref="dataSourceSwitchAspect">      <!--数据源切换可以控制为Dao或者service层,请根据实际业务需要自行决定-->      <aop:pointcut id="dynamicPointCut" expression="execution(* com.xx.xx.xx.dao.*.*(..))"/>      <aop:before method="switchDataSource" pointcut-ref="dynamicPointCut"/>   </aop:aspect></aop:config>

6、使用spring整合mybatis,和一般的整合却别在于使用的数据源为自定义数据源,代码如下:

   
      
         classpath:ModelMapper.xml
         classpath:ModelMapper1.xml
         classpath:ModelMapper2.xml

注意:目前精力有限,此处为什么可以使用自定义多个数据源的底层原理还没来得及看,有兴趣的同学请自行研究,如果好心的话可以简单的告知我,谢谢你了~~~

7、将自定义数据源纳入spring的事务管理器管理,配置代码如下:

<!--事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   <property name="dataSource" ref="dataSource" /></bean><!--申明事务回滚的方法和异常信息--><tx:advice id="txAdvic" transaction-manager="transactionManager">   <tx:attributes>      <tx:method name="do*" read-only="false" propagation="REQUIRED" rollback-for="java.lang.Exception"/>   </tx:attributes></tx:advice><!--申明事务范围--><aop:config>   <aop:pointcut id="txPointCut" expression="execution(* com.xx.xx.xx.service.*.*(..))"/>   <aop:advisor advice-ref="txAdvic" pointcut-ref="txPointCut"/></aop:config>

Model类:

com.yao.yz.yaowangdrug.model;

DBModel {

    String ;

    String ;

    String getValue() {
        ;
    }

    setValue(String value) {
        .= value;
    }

    String getKey() {
        ;
    }

    setKey(String key) {
        .= key;
    }
}

Dao接口:

com.yao.yz.yaowangdrug.dao;

;
com.yao.yz.yaowangdrug.model.DBModel;

DBDao {

    ()
    insert(DBModel dbModel) Exception;

}

Service接口:

com.yao.yz.yaowangdrug.service;

com.yao.yz.yaowangdrug.model.DBModel;
;

DBService {

    doInsert() Exception;

    doUpdate() Exception;

    testSeperateDB() Exception;

}

关于事务的控制,有一下几点说明:

1、采用申明或者注解实现事务控制时时,因为开启了事务控制,所以如果是两个不同的数据源Dao,根据spring的事务传播特性,第二个事务开启将使用已有的事务(即将采用第一个数据源的数据库连接)进行事务操作,所以此时事务控制是失效的(即使切面执行了数据源切换)。结论就是跨数据库的事务是无法通过spring的数据库控制实现的!!!请切记。

2、同一个数据源的事务控制和普通的数据源控制是一致的,没有什么区别。

以上代码都是经过测试通过,可以实现跨库的数据方式,主要的应用场景是mysql的数据库读写分离。如果不正确的地方请告知,谢谢!

时间: 2024-11-10 01:19:59

spring + mybatis + 多数据源整合事务的相关文章

mybatis学习笔记(六) -- maven+spring+mybatis从零开始搭建整合详细过程(下)

继续 mybatis学习笔记(五) -- maven+spring+mybatis从零开始搭建整合详细过程(上) 五.使用监听器启动Spring容器 1.修改pom.xml文件,添加Spring-web 2.修改web.xml,配置启动Spring容器 3.新建BookServer 4.新建BookServlet 5.修改ApplicationContext.xml 6.测试 继续!!! 五.使用监听器启动Spring容器 1.修改pom.xml,添加Spring-web包(注:上一篇中的pom

Spring+SpringMVC+Mybatis 多数据源整合(转)

转载自:http://blog.csdn.net/q908555281/article/details/50316137 目录(?)[-]拷贝所需jar拷贝jar文件需要的jar文件入下图所示因为我的项目中用到了json解析所以导入了json相关的包写一个数据库切换的工具类DataSourceContextHolder用来切换数据库写一个DynamicDataSource类来继承AbstractRoutingDataSource并重写determineCurrentLookupKey方法来达到动

springMVC+spring+mybatis多数据源配置

1.application.properties配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="htt

Spring+mybatis+struts框架整合的配置具体解释

学了非常久的spring+mybatis+struts.一直都是单个的用他们,或者是两两组合用过,今天总算整合到一起了,配置起来有点麻烦.可是配置完一次之后.就轻松多了,那么框架整合配置具体解释例如以下. 1.导入对应的jar包 由于我们建造的是maven的web项目,全部我们在pom.xml中须要导入这些包. pom.xml 具体凝视 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&q

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

本文转载于本人另一博客[http://blog.csdn.net/liaohaojian/article/details/68488150] 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确

mybatis学习笔记(五) -- maven+spring+mybatis从零开始搭建整合详细过程(附demo和搭建过程遇到的问题解决方法)

文章介绍结构一览 一.使用maven创建web项目 1.新建maven项目 2.修改jre版本 3.修改Project Facts,生成WebContent文件夾 4.将WebContent下的两个文件复制到src/main/webapp下,删掉WebContent 5.修改Deployment Assembly 6.测试 二.mybatis访问mysql 1.数据库准备 2.修改pom.xml 3.创建实体类 4.创建访问接口 5.添加映射文件 6.添加MyBatisCfg.xml配置文件,注

SSM(spring mvc+spring+Mybatis)框架整合

最近用Idea开发,idea是一款综合的相对较新的Java IDE.Idea支持很多整合功能,我觉得挺好用的.Idea可以校正xml,支持jsp的调试.最让我喜欢的是,写spring配置文件的时候,写的一些路径都可以自己找到.classpath自己有代码的提示,超级的智能. 环境配置 在整合框架之前,先配置一下JER运行环境,配置maven仓库. 1.File--ProjectStructure--Project--New- 选择jdk的安装环境 2.File--Settings--Maven-

spring事务隔离级别、传播行为以及spring+mybatis+atomikos实现分布式事务管理

转载自:http://blog.csdn.net/liaohaojian/article/details/68488150 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整

spring+mybatis多数据源动态切换

spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web.xml <context-param> <param-name>webAppRootKey</param-name> <param-value>trac</param-value> </context-param> <!-- Spr