• Spring+mybatis多数据源切换笔记


    分两种方式,手动和自动切换,

    前提:使用mybatis自动生成工具生成相关xml,实体类,接口等,spring框架,依赖的jar包都已引入

    1.spring基础配置如下:

    <?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        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-4.3.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
        <!--6 容器自动扫描IOC组件 -->
        <context:component-scan base-package="com.vip"></context:component-scan>
        <!--1 引入属性文件,在配置中占位使用 -->
        <context:property-placeholder location="classpath*:dbt.properties" />
    
        <!-- 配置数据源Master -->
        <bean name="dataSourceMaster" class="com.alibaba.druid.pool.DruidDataSource"
            init-method="init" destroy-method="close">
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.uid}" />
            <property name="password" value="${jdbc.pwd}" />
            <!-- 初始化连接大小 -->
            <property name="initialSize" value="0" />
            <!-- 连接池最大使用连接数量 -->
            <property name="maxActive" value="20" />
            <!-- 连接池最大空闲 -->
            <property name="maxIdle" value="20" />
            <!-- 连接池最小空闲 -->
            <property name="minIdle" value="0" />
            <!-- 获取连接最大等待时间 -->
            <property name="maxWait" value="60000" />
        </bean>
        <!-- 配置数据源Slave -->
        <bean name="dataSourceSlave" class="com.alibaba.druid.pool.DruidDataSource"
            init-method="init" destroy-method="close">
            <property name="url" value="${jdbc2.url}" />
            <property name="username" value="${jdbc2.uid}" />
            <property name="password" value="${jdbc2.pwd}" />
            <!-- 初始化连接大小 -->
            <property name="initialSize" value="0" />
            <!-- 连接池最大使用连接数量 -->
            <property name="maxActive" value="20" />
            <!-- 连接池最大空闲 -->
            <property name="maxIdle" value="20" />
            <!-- 连接池最小空闲 -->
            <property name="minIdle" value="0" />
            <!-- 获取连接最大等待时间 -->
            <property name="maxWait" value="60000" />
        </bean>
    
        <bean id="dataSource" class="com.vip.inventory.mybaisc.ThreadLocalRountingDataSource">
            <property name="defaultTargetDataSource" ref="dataSourceMaster" />
            <property name="targetDataSources">
                <map key-type="com.vip.inventory.mybaisc.DataSources">
                    <entry key="MASTER" value-ref="dataSourceMaster" />
                    <entry key="SLAVE" value-ref="dataSourceSlave" />
                    <!-- 这里还可以加多个dataSource -->
                </map>
            </property>
        </bean>
    
        <!--3 会话工厂bean sqlSessionFactoryBean -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 数据源 -->
            <property name="dataSource" ref="dataSource"></property>
            <!-- 实体类别名 -->
            <property name="typeAliasesPackage" value="com/vip/inventory/entity"></property>
            <!-- sql映射文件路径 -->
            <property name="mapperLocations" value="classpath*:mapper/**/*Mapper.xml"></property>
        </bean>
    
        <!--4 自动扫描对象关系映射 -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
            <!-- 指定要自动扫描接口的基础包,实现接口 -->
            <property name="basePackage" value="com.vip"></property>
        </bean>
    
        <!--5 声明式事务管理 -->
        <!--定义事物管理器,由spring管理事务 -->
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--支持注解驱动的事务管理,指定事务管理器 -->
        <tx:annotation-driven transaction-manager="transactionManager" />
    
    
        <!--7 aspectj支持自动代理实现AOP功能 -->
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
    
    
    
    </beans>
    View Code

    2.数据源配置文件:

    #mysql jdbc
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://ip/test1?useUnicode=true&characterEncoding=UTF-8
    jdbc.uid=uid
    jdbc.pwd=pa
    
    #galaxy jdbc
    jdbc2.driver=com.mysql.jdbc.Driver
    jdbc2.url=jdbc:mysql://ip/test2?useUnicode=true&characterEncoding=UTF-8
    jdbc2.uid=uid
    jdbc2.pwd=pa
    View Code

    3.新建枚举类:

    package com.inventory.mybaisc;
    
    public enum DataSources {
        MASTER, SLAVE
    
    }
    View Code

    注意此枚举值必须对应spring配置文件各数据源的别名

    4.新建DataSourceTypeManager类,具体执行数据源切换

    public class DataSourceTypeManager {
         private static final ThreadLocal<DataSources> dataSourceTypes = new ThreadLocal<DataSources>(){
                @Override
                protected DataSources initialValue(){
                    return DataSources.MASTER;
                }
            };
            
            public static DataSources get(){
                return dataSourceTypes.get();
            }
            
            public static void set(DataSources dataSourceType){
                dataSourceTypes.set(dataSourceType);
            }
            
            public static void reset(){
                dataSourceTypes.set(DataSources.MASTER);
            }
    }
    View Code

    5.新建ThreadLocalRountingDataSource继承AbstractRoutingDataSource,实现切换

    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class ThreadLocalRountingDataSource  extends AbstractRoutingDataSource{
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceTypeManager.get();
        }
    }
    View Code

    一:执行具体mybatis接口时手动切换方式:

    在service层具体调用insert接口进行数据库操作前加入:

    DataSourceTypeManager.set(DataSources.MASTER);

    则,在执行insert时会切换数据源到master

    insert方法为mybatic自动生成的接口,具体如下:

    public interface InventoryMapper {
        int deleteByPrimaryKey(Long id);
        int deleteByItemKey(String item);
        int insert(Inventory record);
    
        int insertSelective(Inventory record);
    
        Inventory selectByPrimaryKey(Long id);
    
        int updateByPrimaryKeySelective(Inventory record);
    
        int updateByPrimaryKey(Inventory record);
    }
    View Code

    二:动态切换mybatic数据源

    通过增加一个切面去拦截servcie层在调用mybatis生成的接口时,来切换数据源,从而省去每次调用mybatis生成的接口时都要手动注明数据源

    AOP代码如下:

    @Aspect // for aop
    @Component // for auto scan
    @Order(0) // execute before @Transactional
    public class DynamicChangeDbSource {
    
        @Pointcut("execution(public * com.inventory.ferrari.service.data.ferrari..*.*(..))")
        public void invanyMethod() {
        };
    
        @Pointcut("execution(public * com.inventory.ferrari.service.data.galaxy..*.*(..))")
        public void galaxyanyMethod() {
        };
    
        @Before("invanyMethod()")
        public void beforeinv(JoinPoint jp) {
            Object[] args = jp.getArgs();
            if(args==null){
                DataSourceTypeManager.set(DataSources.MASTER);
                //return;
            }
            //System.out.println("-------------" + args[0]);
            DataSourceTypeManager.set(DataSources.MASTER);
        }
    
        @Before("galaxyanyMethod()")
        public void beforegalaxy(JoinPoint jp) {
            DataSourceTypeManager.set(DataSources.SLAVE);
        }
    
    }
    View Code

    @Order(0) 注解表示在执行sql前就切换数据源

  • 相关阅读:
    centos执行sudo 显示command not found的问题
    linux(centos)-command
    关于linux(centos)下浏览器(chrome)打开界面缓慢的一个可能解决办法
    verilog 基本语法
    Date 类 (java.util.Date)
    Objects 类
    发红包案例(普通红包和随机红包)
    接口作为方法的参数和返回值
    接口作为成员变量类型
    类作为成员变量类型
  • 原文地址:https://www.cnblogs.com/xianlai-huang/p/7852951.html
Copyright © 2020-2023  润新知