前言
工作中会经常遇到使用多个数据源的场景,我看其他人的博客,要么过分冗余,要么生搬硬套,乱得很。基于这种情况,我将根据公司前后两个项目的经验,整理出三套解决方案,均经产品检测无误。
第一种分享给SSM的小伙伴,这是基于注解达到切换数据源的目的。
第二三种则是sprinboot下的配置。其中:
第二种,是我根据SSM的配置,把他改成了Springboot版本的基于注解的切换数据源。
第三种是我们目前所采纳的方案,我们放弃了注解配置数据源,因为业务场景中,aop处理的注解无法通过dao层直接转换,所以只能注在service层以上的方法中,业务多层套用的情形下,需要单独写个service用于不同源的数据处理显然不是很明智。
总的来说,各有高下,如何选择还需看具体的场景。下面是详细的完成配置。
1.基于注解的SSM配置多数据源
jdbc.properties
jdbc.url=jdbc:mysql://ip:3306/db?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=******
jdbc.url.mdm=jdbc:mysql://ip2:3306/db2?useUnicode=true&characterEncoding=utf-8
jdbc.username.mdm=root
jdbc.password.mdm=******
jdbc.url.pki=jdbc:mysql://ip3:3306/db3?useUnicode=true&characterEncoding=utf-8
jdbc.username.pki=root
jdbc.password.pki=******
STEP1. 在mybatis的配置文件中(spring-common.xml)配置数据源
classpath:conf/configures/jdbc/jdbc.properties
STEP2.代码配置
注解DataSource
package com.ai.util.resource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value();
}
类DataSourceRouter
package com.ai.util.resource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DataSourceRouter extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return HandleDataSource.getDataSource();
}
}
类HandleDataSource
package com.ai.util.resource;
public class HandleDataSource {
private static final ThreadLocal holder = new ThreadLocal();
public static void setDataSource(String datasource) {
holder.set(datasource);
}
public static String getDataSource() {
return holder.get();
}
public static void clearDataSource() {
holder.remove();
}
}
类DataSourceAspect
package com.ai.util.resource;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Aspect
@Component
@Order(1)
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class DataSourceAspect {
static Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
/*@Pointcut("execution(* com.ai..*.service..*.*(..))")*/
@Pointcut("execution(* com.ai.system.service..*.*(..))")
public void aspect() {}
@Before("aspect()")
public void before(JoinPoint point) {
Class> target = point.getTarget().getClass();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod() ;
DataSource dataSource = null ;
dataSource = this.getDataSource(target, method) ;
if(dataSource == null){
for (Class> clazz : target.getInterfaces()) {
dataSource = getDataSource(clazz, method);
if(dataSource != null){
break ;
}
}
}
if(dataSource != null && !"".equals(dataSource.value()) ){
HandleDataSource.setDataSource(dataSource.value());
}
}
@After("aspect()")
public void after(JoinPoint point) {
HandleDataSource.setDataSource(null);
}
public DataSource getDataSource(Class> target, Method method){
try {
Class>[] types = method.getParameterTypes();
Method m = target.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
return m.getAnnotation(DataSource.class);
}
if (target.isAnnotationPresent(DataSource.class)) {
return target.getAnnotation(DataSource.class);
}
} catch (Exception e) {
e.printStackTrace();
logger.error(MessageFormat.format("通过注解切换数据源时发生异常[class={0},method={1}]:"
, target.getName(), method.getName()),e) ;
}
return null ;
}
}
STEP3.使用
service 使用mdm数据源
//终端管控审计查询
@Override
@DataSource("mdm")
public List getTerminalControlList() {
//获取pki所有证书信息
List list = auditDao.selectTerminalControlAuditFromMDM();
HandleDataSource.setDataSource(null);
return list;
}
service 使用pki数据源
//证书审计查看详情页面
@Override
@DataSource("pki")
public List getZssjDataList(CertificateAudit certificateAudit) {
//获取pki所有证书信息
List list = auditDao.selectCertificateAuditDataListFromPKI(certificateAudit);
HandleDataSource.setDataSource(null);
return list;
}
不加注解默认使用的是默认的数据源
2.基于注解的springboot配置多数据源
1.yml配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://ip1:3306/db1?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: ******
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
opcl:
datasource:
url: jdbc:mysql://ip2:3306/db2?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: ******
#是否开启多数据源配置
myconfig:
muti-datasource-open: true
2.两个数据源的配置类
package com.ai.api.config.datasource.properties;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.JdbcConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
/**
* @Author yonyong
* @Description // * 数据库数据源配置
* 说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在"application.yml"中配置即可
* @Date 2020/3/4 18:03
**/
@Component
@ConfigurationProperties(prefix = "spring.datasource")
public class DruidProperties {
private String url;
private String username;
private String password;
private String driverClassName = "com.mysql.jdbc.Driver";
private Integer initialSize = 10;
private Integer minIdle = 3;
private Integer maxActive = 60;
private Integer maxWait = 60000;
private Boolean removeAbandoned = true;
private Integer removeAbandonedTimeout = 180;
private Integer timeBetweenEvictionRunsMillis = 60000;
private Integer minEvictableIdleTimeMillis = 300000;
private String validationQuery = "SELECT 'x'";
private Boolean testWhileIdle = true;
private Boolean testOnBorrow = false;
private Boolean testOnReturn = false;
private Boolean poolPreparedStatements = true;
private Integer maxPoolPreparedStatementPerConnectionSize = 50;
private String filters = "stat";
public void config(DruidDataSource dataSource) {
dataSource.setDbType(JdbcConstants.MYSQL);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driverClassName);
dataSource.setInitialSize(initialSize); // 定义初始连接数
dataSource.setMinIdle(minIdle); // 最小空闲
dataSource.setMaxActive(maxActive); // 定义最大连接数
dataSource.setMaxWait(maxWait); // 获取连接等待超时的时间
dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收
dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 配置一个连接在池中最小生存的时间,单位是毫秒
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 用来检测连接是否有效的sql,要求是一个查询语句
dataSource.setValidationQuery(validationQuery);
// 申请连接的时候检测
dataSource.setTestWhileIdle(testWhileIdle);
// 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能
dataSource.setTestOnBorrow(testOnBorrow);
// 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能
dataSource.setTestOnReturn(testOnReturn);
// 打开PSCache,并且指定每个连接上PSCache的大小
dataSource.setPoolPreparedStatements(poolPreparedStatements);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
// 监控统计用的filter:stat
// 日志用的filter:log4j
// 防御SQL注入的filter:wall
try {
dataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public Integer getInitialSize() {
return initialSize;
}
public void setInitialSize(Integer initialSize) {
this.initialSize = initialSize;
}
public Integer getMinIdle() {
return minIdle;
}
public void setMinIdle(Integer minIdle) {
this.minIdle = minIdle;
}
public Integer getMaxActive() {
return maxActive;
}
public void setMaxActive(Integer maxActive) {
this.maxActive = maxActive;
}
public Integer getMaxWait() {
return maxWait;
}
public void setMaxWait(Integer maxWait) {
this.maxWait = maxWait;
}
public Integer getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public Integer getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public Boolean getTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(Boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public Boolean getTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(Boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public Boolean getTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(Boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public Boolean getPoolPreparedStatements() {
return poolPreparedStatements;
}
public void setPoolPreparedStatements(Boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}
public Integer getMaxPoolPreparedStatementPerConnectionSize() {
return maxPoolPreparedStatementPerConnectionSize;
}
public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public Boolean getRemoveAbandoned() {
return removeAbandoned;
}
public void setRemoveAbandoned(Boolean removeAbandoned) {
this.removeAbandoned = removeAbandoned;
}
public Integer getRemoveAbandonedTimeout() {
return removeAbandonedTimeout;
}
public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {
this.removeAbandonedTimeout = removeAbandonedTimeout;
}
}
package com.ai.api.config.datasource.properties;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @Author yonyong
* @Description //多数据源的配置
* @Date 2020/3/4 18:03
* @Param
* @return
**/
@Component
@ConfigurationProperties(prefix = "opcl.datasource")
public class MutiDataSourceProperties {
private String url;
private String username;
private String password;
public void config(DruidDataSource dataSource) {
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3.注解及其他
package com.ai.api.config.datasource;
import java.lang.annotation.*;
/**
* @Author yonyong
* @Description //多数据源标识
* @Date 2020/3/4 17:12
* @Param
* @return
**/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {
String name() default "";
}
package com.ai.api.config.datasource;
public class DataSourceContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal();
/**
* @param dataSourceType 数据库类型
* @Description: 设置数据源类型
*/
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
/**
* @Description: 获取数据源类型
*/
public static String getDataSourceType() {
return contextHolder.get();
}
/**
* @Description: 清除数据源类型
*/
public static void clearDataSourceType() {
contextHolder.remove();
}
}
package com.ai.api.config.datasource;
public interface DSEnum {
String DATA_SOURCE_DEFAULT = "dataSourceCore"; //核心数据源
String DATA_SOURCE_OPCL = "dataSourceOpcl"; //opcl数据源
}
package com.ai.api.config.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
4.核心 切面
package com.ai.api.config.datasource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @Author yonyong
* @Description //多数据源切换的aop
* @Date 2020/3/4 18:02
* @Param
* @return
**/
@Aspect
@Component
@ConditionalOnProperty(prefix = "myconfig", name = "muti-datasource-open", havingValue = "true")
public class MultiSourceExAop implements Ordered {
private Logger log = LoggerFactory.getLogger(MultiSourceExAop.class);
@Pointcut(value = "@annotation( com.ai.api.config.datasource.DataSource)")
private void cut() {
}
@Around("cut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Signature signature = point.getSignature();
MethodSignature methodSignature = null;
if (!(signature instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
methodSignature = (MethodSignature) signature;
Object target = point.getTarget();
Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
DataSource datasource = currentMethod.getAnnotation(DataSource.class);
if (datasource != null) {
DataSourceContextHolder.setDataSourceType(datasource.name());
log.debug("设置数据源为:" + datasource.name());
} else {
DataSourceContextHolder.setDataSourceType(DSEnum.DATA_SOURCE_DEFAULT);
log.debug("设置数据源为:dataSourceDefault");
}
try {
return point.proceed();
} finally {
log.debug("清空数据源信息!");
DataSourceContextHolder.clearDataSourceType();
}
}
/**
* aop的顺序要早于spring的事务
*/
@Override
public int getOrder() {
return 1;
}
}
5.mybatis配置,也是必须
package com.ai.api.config.datasource;
import com.ai.api.config.datasource.properties.DruidProperties;
import com.ai.api.config.datasource.properties.MutiDataSourceProperties;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.sql.SQLException;
import java.util.HashMap;
@Configuration
@EnableTransactionManagement(order = 2)
@MapperScan(basePackages = {"com.ai.api.mapper"})
public class MybatisConfig {
@Autowired
DruidProperties druidProperties;
@Autowired
MutiDataSourceProperties mutiDataSourceProperties;
/**
* 核心数据源
*/
private DruidDataSource defaultDataSource() {
DruidDataSource dataSource = new DruidDataSource();
druidProperties.config(dataSource);
return dataSource;
}
/**
* 另一个数据源
*/
private DruidDataSource opclDataSource() {
DruidDataSource dataSource = new DruidDataSource();
druidProperties.config(dataSource);
mutiDataSourceProperties.config(dataSource);
return dataSource;
}
/**
* 单数据源连接池配置
*/
@Bean
@ConditionalOnProperty(prefix = "myconfig", name = "muti-datasource-open", havingValue = "false")
public DruidDataSource singleDatasource() {
return defaultDataSource();
}
/**
* 多数据源连接池配置
*/
@Bean
@ConditionalOnProperty(prefix = "myconfig", name = "muti-datasource-open", havingValue = "true")
public DynamicDataSource mutiDataSource() {
DruidDataSource defaultDataSource = defaultDataSource();
DruidDataSource opclDataSource = opclDataSource();
try {
defaultDataSource.init();
opclDataSource.init();
} catch (SQLException sql) {
sql.printStackTrace();
}
DynamicDataSource dynamicDataSource = new DynamicDataSource();
HashMap
3.非注解配置的基于springboot配置多数据源
application.yml
# DataSource Config
hikari:
eoms:
jdbc-url: jdbc:mysql://ip:3306/db?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: ******
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCPOfEoms
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
validation-timeout: 5000
opcl:
jdbc-url: jdbc:mysql://ip2:3306/db2?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: ******
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCPOfOpcl
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
validation-timeout: 5000
STEP1给每个数据源新建一个配置文件
eoms
package com.ai.api.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.ai.api.mapper.eoms",
sqlSessionTemplateRef = "eomsSqlSessionTemplate")
public class EomsDataSourceConfig {
/*生成数据源*/
@Bean(name = "eomsDs")
@ConfigurationProperties(prefix = "hikari.eoms")
@Primary
public DataSource createDataSource() {
return DataSourceBuilder.create().build();
}
/*创建 SqlSessionFactory*/
@Bean(name = "eomsSqlSessionFactory")
@Primary
public SqlSessionFactory createSqlSessionFactory(@Qualifier("eomsDs") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/eoms/*.xml"));
return bean.getObject();
}
/*配置事务管理*/
@Bean(name = "eomsTransactionManager")
@Primary
public DataSourceTransactionManager createTransactionManager(@Qualifier("eomsDs") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/*SqlSessionTemplate是MyBatis-Spring的核心。这个类负责管理MyBatis的SqlSession,调用MyBatis的SQL方法*/
@Bean(name = "eomsSqlSessionTemplate")
@Primary
public SqlSessionTemplate createSqlSessionTemplate(@Qualifier("eomsSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
opcl
package com.ai.api.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.ai.api.mapper.opcl",
sqlSessionTemplateRef = "opclSqlSessionTemplate")
public class OpclDataSourceConfig {
@Bean(name = "opclDs")
@ConfigurationProperties(prefix = "hikari.opcl")
public DataSource createDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "opclSqlSessionFactory")
public SqlSessionFactory createSqlSessionFactory(@Qualifier("opclDs") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/opcl/*.xml"));
return bean.getObject();
}
@Bean(name = "opclTransactionManager")
public DataSourceTransactionManager createTransactionManager(@Qualifier("opclDs") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "opclSqlSessionTemplate")
public SqlSessionTemplate createSqlSessionTemplate(@Qualifier("opclSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
STEP2.在dao层的两个mapper包下分别新建两个对应的存放接口及xml文件的文件夹:eoms文件夹和opcl文件夹(在上边的类中有配置,存放在这两个文件夹下)
STEP3.新建mapper接口时,需要加上对应的注解
eoms
package com.ai.api.mapper.eoms;
import com.ai.api.model.BatchHandlerRecords;
import com.ai.api.model.GateWay;
import com.ai.api.model.TerminalControl;
import org.springframework.beans.factory.annotation.Qualifier;
import com.ai.api.model.UserAction;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @Author yonyong
* @Description //审计管理
* @Date 2020/3/3 10:40
* @Param
* @return
**/
@Qualifier("eomsSqlSessionTemplate")
public interface AuditMapper {
//查询总记录数
Integer selectTerminalControlCount(@Param("TerminalControl")TerminalControl TerminalControl);
}
opcl
package com.ai.api.mapper.opcl;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.Map;
@Qualifier("opclSqlSessionTemplate")
public interface LoginMapper {
Map getAdmin(int id);
}