Spring Boot +Mybatis+druid动态多数据源自由切换

Spring Boot +Mybatis+druid动态多数据源自由切换

实现数据源动态切换,希望能帮到需要的人,代码copy就能用

  1. pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.7.RELEASE</version>
    </parent>

    <groupId>com.crr.zgl</groupId>
    <artifactId>api</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <jackson-dataformat-yaml.version>2.8.3</jackson-dataformat-yaml.version>
        <junit.version>4.12</junit.version>
        <log4j.version>2.6.2</log4j.version>
        <druid.version>1.1.3</druid.version>
        <apache-commons-pool2.version>2.4.2</apache-commons-pool2.version>
        <mysql-connector-java.version>6.0.5</mysql-connector-java.version>
        <mybatis-spring-boot-starter.version>1.1.1</mybatis-spring-boot-starter.version>
        <jersey-client.version>2.23.1</jersey-client.version>
        <jedis.version>2.9.0</jedis.version>
        <apache-commons-lang3.version>3.4</apache-commons-lang3.version>
        <commons-lang.version>2.6</commons-lang.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency> <!--mysql java驱动-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>
        <dependency><!--parse yaml-->
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-yaml</artifactId>
            <version>${jackson-dataformat-yaml.version}</version>
        </dependency>
        <dependency><!--回归测试框架-->
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>

        <dependency><!-- log4j2 2个核心包之一 -->
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency><!--JDBC连接池、监控组件-->
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <dependency><!--Tomcat Jdbc Pool 数据库连接池-->
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>${apache-commons-pool2.version}</version>
        </dependency>

        <dependency><!--tomcat 自带jdbc-->
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>

        <dependency> <!--mysql java驱动-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>

        <dependency><!--是JAX-RS(JSR311)开源参考实现用于构建RESTful Web service-->
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey-client.version}</version>
        </dependency>

        <dependency><!--redis 客户端-->
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
        </dependency>

        <dependency> <!-- 引入log4j2依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>  <!-- 加上这个才能辨认到log4j2.yml文件 -->
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-yaml</artifactId>
        </dependency>
        <dependency><!--包含大量和JavaBean操作有关的工具方法-->
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <exclusions>
                <exclusion><!--使用抽象的API记录日志,这些API都是实现无关的-->
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency><!--是基于JDK API开发一系列公共基础类,涉及到数组工具类,字符串工具类,字符工具类,数学方面,时间日期工具类,异常,事件等工具类-->
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${apache-commons-lang3.version}</version>
        </dependency>

        <dependency><!--主要是一些公共的工具集合,比如对字符、数组的操作等等-->
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons-lang.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.3-beta</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-client</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
    </dependencies>


    <build>
        <finalName>api</finalName>
        <resources>
            <resource>
                <directory>${basedir}/src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <!-- 是否替换资源中的属性-->
                <filtering>false</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  1. 数据源配置

spring.datasource.masterMapperLocations=classpath:com/rrc/zgl/dao/*/impl/*Mapper.xml
#master数据源
spring.datasource.master.url=jdbc:mysql://localhost:3306/zgl?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
spring.datasource.master.username=root
spring.datasource.master.password=123456
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.master.initialSize=5
spring.datasource.master.minIdle=5
spring.datasource.master.maxActive= 20
spring.datasource.master.maxWait= 60000
spring.datasource.master.timeBetweenEvictionRunsMillis= 60000
spring.datasource.master.minEvictableIdleTimeMillis= 300000
spring.datasource.master.validationQuery= SELECT 1 
spring.datasource.master.testWhileIdle= true
spring.datasource.master.testOnBorrow= false
spring.datasource.master.testOnReturn= false
spring.datasource.master.poolPreparedStatements= true
spring.datasource.master.maxPoolPreparedStatementPerConnectionSize= 20
spring.datasource.master.filters= stat,wall,log4j
spring.datasource.master.connectionProperties= druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.master.useGlobalDataSourceStat= true


#cluster数据源
spring.datasource.cluster.url=jdbc:mysql://localhost:3306/zgl1?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
spring.datasource.cluster.username=root
spring.datasource.cluster.password=123456
spring.datasource.cluster.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.cluster.initialSize=5
spring.datasource.cluster.minIdle=5
spring.datasource.cluster.maxActive= 20
spring.datasource.cluster.maxWait= 60000
spring.datasource.cluster.timeBetweenEvictionRunsMillis= 60000
spring.datasource.cluster.minEvictableIdleTimeMillis= 300000
spring.datasource.cluster.validationQuery= SELECT 1 
spring.datasource.cluster.testWhileIdle= true
spring.datasource.cluster.testOnBorrow= false
spring.datasource.cluster.testOnReturn= false
spring.datasource.cluster.poolPreparedStatements= true
spring.datasource.cluster.maxPoolPreparedStatementPerConnectionSize= 20
spring.datasource.cluster.filters= stat,wall,log4j
spring.datasource.cluster.connectionProperties= druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.cluster.useGlobalDataSourceStat= true
  1. 启动类
@SpringBootApplication
@PropertySource(value = {"classpath:dataSource.properties"})
@ServletComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4.配置数据源1

@Configuration
@EnableTransactionManagement
public class ClusterDruidDataSourceConfig {
    @Value("${spring.datasource.masterMapperLocations}")
    private String clusterMapperLocations;

    @ConfigurationProperties(prefix = "spring.datasource.cluster")
    @Bean(name = "clusterDataSource")
    public DataSource clusterDataSource() {
        return new DruidDataSource();
    }

    /**
     * SqlSessionFactory配置
     *
     * @return
     * @throws Exception
     */
    @Bean(name = "clusterSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(
            @Qualifier("clusterDataSource") DataSource dataSource
    ) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        //配置mapper文件位置
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(clusterMapperLocations));

        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 配置事物管理器
     *
     * @return
     */
    @Bean(name = "clusterTransactionManager")
    public DataSourceTransactionManager clusterTransactionManager(
            @Qualifier("clusterDataSource") DataSource dataSource
    ) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
  1. 数据源2
@Configuration
@EnableTransactionManagement
public class MasterDruidDataSourceConfig {

    @Value("${spring.datasource.masterMapperLocations}")
    private String masterMapperLocations;

    @ConfigurationProperties(prefix = "spring.datasource.master")
    @Bean(name = "masterDataSource")
    @Primary
    public DataSource masterDataSource() {
        return new DruidDataSource();
    }

    /**
     * SqlSessionFactory配置
     *
     * @return
     * @throws Exception
     */
    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(
            @Qualifier("masterDataSource") DataSource dataSource
    ) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 配置mapper文件位置
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(masterMapperLocations));
        return sqlSessionFactoryBean.getObject();
    }
    /**
     * 配置事物管理器
     *
     * @return
     */
    @Bean(name = "masterTransactionManager")
    @Primary
    public DataSourceTransactionManager masterTransactionManager(
            @Qualifier("masterDataSource") DataSource dataSource
    ) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}
  1. 数据源动态切换
@Aspect
@Component
public class DynamicDataSourceAspect {
    private Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    @Around("execution(* com.crr.zgl.dao..*.*(..))")
    public Object  around(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        boolean methodAnnotation = method.isAnnotationPresent(TargetDataSource.class);

        TargetDataSource targetDataSource = null;
        if (methodAnnotation) {
            targetDataSource = method.getAnnotation(TargetDataSource.class);
        } else {
            Class clazz[] = pjp.getTarget().getClass().getInterfaces();
            targetDataSource = (TargetDataSource) clazz[0].getAnnotation(TargetDataSource.class);
        }
        if (targetDataSource != null) {
            DynamicDataSourceHolder.setDataSource(targetDataSource.dataSource());
            logger.debug("mybatis接口: " + (method.getDeclaringClass() + "." + method.getName()) + " 设置数据源 key is " + targetDataSource.dataSource());
        }
        Object result = pjp.proceed();//执行方法
        DynamicDataSourceHolder.clearDataSource();
        return result;
    }
}
  1. 数据源切换
/**
 * 多数据进行切换
 */
public class DynamicDataSourceHolder {
        //使用ThreadLocal把数据源与当前线程绑定
        private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();

        public static void setDataSource(String dataSourceName) {
            dataSources.set(dataSourceName);
        }

        public static String getDataSource() {
            return (String) dataSources.get();
        }

        public static void clearDataSource() {
            dataSources.remove();
        }
    }
  1. 获取数据源
/**
 * 动态数据源获取sessionfactory
 * @Author:zhangguangliang
 */
public class DynamicSqlSessionTemplate extends SqlSessionTemplate {

    private static Logger logger = LoggerFactory.getLogger(DynamicSqlSessionTemplate.class);

    private SqlSessionFactory sqlSessionFactory;
    private ExecutorType executorType;
    private SqlSession sqlSessionProxy;
    private PersistenceExceptionTranslator exceptionTranslator;
    private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
    private SqlSessionFactory defaultTargetSqlSessionFactory;

    public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
        this.targetSqlSessionFactorys = targetSqlSessionFactorys;
    }

    public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
        this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
    }

    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
    }

    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
        this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
    }

    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        super(sqlSessionFactory, executorType, exceptionTranslator);
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor());
        this.defaultTargetSqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public SqlSessionFactory getSqlSessionFactory() {
        String dataSourceType = DynamicDataSourceHolder.getDataSource();
        SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(dataSourceType);
        if (targetSqlSessionFactory != null) {
            return targetSqlSessionFactory;
        } else if (defaultTargetSqlSessionFactory != null) {
            if (dataSourceType != null) {
                logger.warn("此[" + dataSourceType + "]dataSourceType未配置文件中配置targetSqlSessionFactorys,将会返回defaultTargetSqlSessionFactory来执行后面的操作");
            }
            return defaultTargetSqlSessionFactory;
        } else {
            Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
            Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
        }
        return this.sqlSessionFactory;
    }

    @Override
    public Configuration getConfiguration() {
        return this.getSqlSessionFactory().getConfiguration();
    }
    @Override
    public ExecutorType getExecutorType() {
        return this.executorType;
    }
    @Override
    public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
        return this.exceptionTranslator;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T selectOne(String statement) {
        return this.sqlSessionProxy.<T>selectOne(statement);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T selectOne(String statement, Object parameter) {
        return this.sqlSessionProxy.<T>selectOne(statement, parameter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
        return this.sqlSessionProxy.<K, V>selectMap(statement, mapKey);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
        return this.sqlSessionProxy.<K, V>selectMap(statement, parameter, mapKey);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
        return this.sqlSessionProxy.<K, V>selectMap(statement, parameter, mapKey, rowBounds);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <E> List<E> selectList(String statement) {
        return this.sqlSessionProxy.<E>selectList(statement);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        return this.sqlSessionProxy.<E>selectList(statement, parameter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        return this.sqlSessionProxy.<E>selectList(statement, parameter, rowBounds);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void select(String statement, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, handler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void select(String statement, Object parameter, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, parameter, handler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int insert(String statement) {
        return this.sqlSessionProxy.insert(statement);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int insert(String statement, Object parameter) {
        return this.sqlSessionProxy.insert(statement, parameter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int update(String statement) {
        return this.sqlSessionProxy.update(statement);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int update(String statement, Object parameter) {
        return this.sqlSessionProxy.update(statement, parameter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int delete(String statement) {
        return this.sqlSessionProxy.delete(statement);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int delete(String statement, Object parameter) {
        return this.sqlSessionProxy.delete(statement, parameter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void commit() {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void commit(boolean force) {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void rollback() {
        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void rollback(boolean force) {
        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void close() {
        throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clearCache() {
        this.sqlSessionProxy.clearCache();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Connection getConnection() {
        return this.sqlSessionProxy.getConnection();
    }

    /**
     * {@inheritDoc}
     *
     * @since 1.0.2
     */
    @Override
    public List<BatchResult> flushStatements() {
        return this.sqlSessionProxy.flushStatements();
    }

    /**
     * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also unwraps exceptions thrown by
     * {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to the {@code PersistenceExceptionTranslator}.
     */
    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession sqlSession = getSqlSession(DynamicSqlSessionTemplate.this.getSqlSessionFactory(), DynamicSqlSessionTemplate.this.executorType, DynamicSqlSessionTemplate.this.exceptionTranslator);
            try {
                Object result = method.invoke(sqlSession, args);
                if (!isSqlSessionTransactional(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory())) {
                    // force commit even on non-dirty sessions because some databases require / a commit/rollback before calling close()
                    sqlSession.commit(true);
                }
                return result;
            } catch (Throwable t) {
                Throwable unwrapped = unwrapThrowable(t);
                if (DynamicSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
                    closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());
                    sqlSession = null;
                    Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }
                throw unwrapped;
            } finally {
                if (sqlSession != null) {
                    closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());
                }
            }
        }
    }
}



/**
 * 反射工具类
 * 
 * @Author:zhangguangliang
 * @Time:2017年9月16日14:44:10
 */
public class ReflectionUtil extends ReflectionUtils {

    private static Logger logger = LoggerFactory.getLogger(ReflectionUtil.class);

    /**
     * 获取obj对象fieldName的Field
     * 
     * @param obj
     * @param fieldName
     * @return
     */
    public static Field getFieldByFieldName(Object obj, String fieldName) {
        if (obj == null || fieldName == null) {
            return null;
        }
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (Exception e) {

            }
        }
        return null;
    }

    /**
     * 获取obj对象fieldName的属性值
     * 
     * @param obj
     * @param fieldName
     * @return
     */
    public static Object getValueByFieldName(Object obj, String fieldName) {
        Object value = null;
        try {
            Field field = getFieldByFieldName(obj, fieldName);
            if (field != null) {
                if (field.isAccessible()) {
                    value = field.get(obj);
                } else {
                    field.setAccessible(true);
                    value = field.get(obj);
                    field.setAccessible(false);
                }
            }
        } catch (Exception e) {
            logger.error("更加属性名称获取属性值异常:");
        }
        return value;
    }

    /**
     * 获取obj对象fieldName的属性值
     * 
     * @param obj
     * @param fieldName
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getValueByFieldType(Object obj, Class<T> fieldType) {
        Object value = null;
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                Field[] fields = superClass.getDeclaredFields();
                for (Field f : fields) {
                    if (f.getType() == fieldType) {
                        if (f.isAccessible()) {
                            value = f.get(obj);
                            break;
                        } else {
                            f.setAccessible(true);
                            value = f.get(obj);
                            f.setAccessible(false);
                            break;
                        }
                    }
                }
                if (value != null) {
                    break;
                }
            } catch (Exception e) {
                 logger.error("更加属性类型获取属性值异常:");
            }
        }
        return (T) value;
    }

    /**
     * 设置obj对象fieldName的属性值
     * 
     * @param obj
     * @param fieldName
     * @param value
     * @throws SecurityException
     * @throws NoSuchFieldException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static boolean setValueByFieldName(Object obj, String fieldName, Object value) {
        try {
            // java.lang.Class.getDeclaredField()方法用法实例教程 -
            // 方法返回一个Field对象,它反映此Class对象所表示的类或接口的指定已声明字段。
            // 此方法返回这个类中的指定字段的Field对象
            Field field = obj.getClass().getDeclaredField(fieldName);
            /**
             * public void setAccessible(boolean flag) throws SecurityException将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 首先,如果存在安全管理器,则在
             * ReflectPermission("suppressAccessChecks") 权限下调用 checkPermission 方法。 如果 flag 为 true,并且不能更改此对象的可访问性(例如,如果此元素对象是 Class 类的 Constructor 对象),则会引发 SecurityException。 如果此对象是 java.lang.Class 类的 Constructor 对象,并且
             * flag 为 true,则会引发 SecurityException。 参数: flag - accessible 标志的新值 抛出: SecurityException - 如果请求被拒绝。
             */
            if (field.isAccessible()) {// 获取此对象的 accessible 标志的值。
                field.set(obj, value);// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
            } else {
                field.setAccessible(true);
                field.set(obj, value);
                field.setAccessible(false);
            }
            return true;
        } catch (Exception e) {
            logger.error("更加属性名称设置属性值异常:");
        }
        return false;
    }

    /**
     * 执行某对象的方法
     * 
     * @param owner
     * @param methodName
     * @param args
     * @return
     * @throws Exception
     */
    public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
        Class<? extends Object> cls = owner.getClass();
        @SuppressWarnings("rawtypes")
        Class[] argclass = new Class[args.length];
        for (int i = 0, j = argclass.length; i < j; i++) {
            argclass[i] = args[i].getClass();
        }
        Method method = cls.getMethod(methodName, argclass);
        return method.invoke(owner, args);
    }

    /**
     * 执行静态类的方法
     * 
     * @param className
     * @param methodName
     * @param args
     * @return
     * @throws Exception
     */
    public Object invokeStaticMethod(String className, String methodName, Object[] args) throws Exception {
        Class<?> cls = Class.forName(className);
        @SuppressWarnings("rawtypes")
        Class[] argclass = new Class[args.length];
        for (int i = 0, j = argclass.length; i < j; i++) {
            argclass[i] = args[i].getClass();
        }
        Method method = cls.getMethod(methodName, argclass);
        return method.invoke(null, args);
    }

    public Object newInstance(String className, Object[] args) throws Exception {
        Class<?> clss = Class.forName(className);
        @SuppressWarnings("rawtypes")
        Class[] argclass = new Class[args.length];
        for (int i = 0, j = argclass.length; i < j; i++) {
            argclass[i] = args[i].getClass();
        }
        Constructor<?> cons = clss.getConstructor(argclass);
        return cons.newInstance();
    }

}
  1. druid配置类
@WebFilter(filterName="druidWebStatFilter",urlPatterns="/*",
    initParams={
        @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源
})
public class DruidStatFilter extends WebStatFilter {

}

@WebServlet(urlPatterns = "/druid/*",
        initParams = {
                @WebInitParam(name = "allow", value = "127.0.0.1"),// IP白名单 (没有配置或者为空,则允许所有访问)
                //@WebInitParam(name="deny",value="192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
                //@WebInitParam(name="loginUsername",value="zgl"),// 用户名
                //@WebInitParam(name="loginPassword",value="zgl"),// 密码
                @WebInitParam(name = "resetEnable", value = "false")// 禁用HTML页面上的“Reset All”功能
        })
public class DruidStatViewServlet extends StatViewServlet {

    // 按照BeanId来拦截配置 用来bean的监控
   /* @Bean(value = "druid-stat-interceptor")
    public DruidStatInterceptor DruidStatInterceptor() {
        DruidStatInterceptor druidStatInterceptor = new DruidStatInterceptor();
        return druidStatInterceptor;
    }

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        // 设置要监控的bean的id
        beanNameAutoProxyCreator.setBeanNames("clusterSqlSessionFactory","masterTransactionManager");
        beanNameAutoProxyCreator.setInterceptorNames("druid-stat-interceptor");
        return beanNameAutoProxyCreator;
    }*/

}
  1. 使用
@TargetDataSource(dataSource = DataSourceConfig.masterDataSource_)
@Repository(value = "userMapper")
public interface UserMapper {
    int deleteByPrimaryKey(Long id);
    @TargetDataSource(dataSource = DataSourceConfig.clusterDataSource_)
    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Long id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}


@Transactional(transactionManager = "clusterTransactionManager",rollbackFor=Exception.class)
    public String test() {
        User user = new User();
        user.setName("124");
        user.setPassword("setPassword");
        int insert1 = zgl1UserMapper.insert(user);
        //int insert = userMapper.insert(user);
        return "success";
    }
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
对于使用 MySQL、MyBatisDruid 实现多数据源配置,你可以按照以下步骤进行操作: 1. 添加相关依赖:在你的项目中,首先需要添加 MySQL、MyBatisDruid 的相关依赖。你可以在项目的 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>版本号</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>版本号</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>版本号</version> </dependency> ``` 请确保将 `版本号` 替换为你所需的实际版本。 2. 配置数据源:在 `application.properties` 或 `application.yml` 文件中配置数据源的相关信息。以下是一个示例配置: ```yaml spring: datasource: master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username: root password: password slave: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/slave_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username: root password: password ``` 这里使用了两个数据源,一个是 `master`,另一个是 `slave`。你可以根据实际情况进行配置。 3. 配置 Druid 连接池:在 `application.properties` 或 `application.yml` 文件中配置 Druid 连接池的相关信息。以下是一个示例配置: ```yaml spring: datasource: druid: initial-size: 5 min-idle: 5 max-active: 20 test-on-borrow: true validation-query: SELECT 1 ``` 这里配置了 Druid 连接池的一些常用参数,你可以根据实际需求进行调整。 4. 配置 MyBatis:创建 MyBatis 的配置文件,例如 `MyBatisConfig.java`,并在其中配置数据源和相关的 MyBatis 设置。以下是一个示例配置: ```java @Configuration @MapperScan(basePackages = "com.example.mapper", sqlSessionTemplateRef = "sqlSessionTemplate") public class MyBatisConfig { @Primary @Bean(name = "masterDataSource") @ConfigurationProperties(prefix = "spring.datasource.master") public DataSource masterDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "slaveDataSource") @ConfigurationProperties(prefix = "spring.datasource.slave") public DataSource slaveDataSource() { return DruidDataSourceBuilder.create().build(); } @Primary @Bean(name = "sqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dynamicDataSource(masterDataSource, slaveDataSource)); return sessionFactory.getObject(); } @Bean(name = "sqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) { DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(); Map<Object, Object> dataSourceMap = new HashMap<>(); dataSourceMap.put("master", masterDataSource); dataSourceMap.put("slave", slaveDataSource); dynamicRoutingDataSource.setDefaultTargetDataSource(masterDataSource); dynamicRoutingDataSource.setTargetDataSources(dataSourceMap); return dynamicRoutingDataSource; } } ``` 在这个配置类中,我们创建了两个数据源 `masterDataSource` 和 `slaveDataSource`,并将它们注入到 `dynamicDataSource` 中。通过 `DynamicRoutingDataSource` 来实现动态切换数据源。 5. 创建 Mapper 接口和 XML 文件:按照正常的 MyBatis 开发流程,创建 Mapper 接口和对应的 XML 文件,并在其中编写 SQL 语句。 完成上述步骤后,你就成功地配置了 MySQL、MyBatisDruid多数据源。你可以根据需要在不同的业务中使用不同的数据源。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值