#端口
server.port: 7788
spring.application.name: bddemo
# mysql
spring.datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#数据库1
db1:
jdbc-url: jdbc:mysql://127.0.0.1:3306/db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
#数据库2
db2:
jdbc-url: jdbc:mysql://127.0.0.1:3306/db2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
# mybatis
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: ccom.example.demo.*.entity
import com.example.demo.utils.DataSourceUtil;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源类
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceUtil.getDB();
}
}
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据库配置
*/
@Configuration
public class DataSourceConfig {
/**
* 数据源1
* spring.datasource.db1:application.properteis中对应属性的前缀
* @return
*/
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource dataSourceOne() {
return DataSourceBuilder.create().build();
}
/**
* 数据源2
* spring.datasource.db2:application.properteis中对应属性的前缀
* @return
*/
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSourceTwo() {
return DataSourceBuilder.create().build();
}
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSourceOne());
// 配置多数据源
Map
/**
* 数据源切换工具
*/
public class DataSourceUtil {
/**
* 默认数据源
*/
public static final String DEFAULT_DS = "db1";
/**
* 数据源属于一个公共的资源
* 采用ThreadLocal可以保证在多线程情况下线程隔离
*/
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源名
* @param dbType
*/
public static void setDB(String dbType) {
contextHolder.set(dbType);
}
/**
* 获取数据源名
* @return
*/
public static String getDB() {
return (contextHolder.get());
}
/**
* 清除数据源名
*/
public static void clearDB() {
contextHolder.remove();
}
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
//移除默认数据库配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DbDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DbDemoApplication.class, args);
}
}
DataSourceUtil.setDB("db2");
spring:
profile: dev
datasource:
db1:
url: jdbc:oracle:thin:@ip:1521/center
username: xxx
password: xxx
initialSize: 1
minIdle: 1
maxActive: 5
driverClassName: oracle.jdbc.driver.OracleDriver
db2:
url: jdbc:mysql://xxx:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&autoReconnectForPools=true&allowMultiQueries=true
username: xxx
password: xxx
initialSize: 1
minIdle: 1
maxActive: 5
driverClassName: com.mysql.cj.jdbc.Driver
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Version 1.0
*/
@Component
@ConfigurationProperties(
prefix = "spring.datasource.db1"
)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DruidProperties1 {
/**
* mysql地址
*/
private String url;
/**
* mysql用户名
*/
private String username;
/**
* mysql加密密码
*/
private String password;
/**
* mysql类加载器
*/
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
}
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(basePackages = "xxx.dao1.**", sqlSessionFactoryRef = "firstSqlSessionFactory")
public class DataSourceConfig1 {
@Autowired
private DruidProperties1 druidProperties1;
@Bean
DataSource firstDataSource() throws SQLException {
log.info("=================start init dataSource1===================");
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(this.druidProperties1.getUrl());
druidDataSource.setUsername(this.druidProperties1.getUsername());
druidDataSource.setPassword(this.druidProperties1.getPassword());
druidDataSource.setDriverClassName(this.druidProperties1.getDriverClassName());
druidDataSource.setInitialSize(this.druidProperties1.getInitialSize());
druidDataSource.setMinIdle(this.druidProperties1.getMinIdle());
druidDataSource.setMaxActive(this.druidProperties1.getMaxActive());
return druidDataSource;
}
@Bean("firstSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource")DataSource dataSource) throws Exception {
List list = new ArrayList();
list.addAll(Arrays.asList(new PathMatchingResourcePatternResolver().getResources("classpath:mapper1/*.xml")));
Resource[] mapperLocations = new Resource[list.size()];
for (int i=0;i
注解说明:
Spring提供的AOP功能有两种实现方式,可选值有PROXY 和 ASPECTJ,默认值为AdviceMode.PROXY。
一种是Spring自带的AOP功能,主要靠JDK代理和CGLIB代理实现,另外一种是通过第三方框架ASPECTJ实现。
@EnableTransactionManagement中的mode选项就是设定Spring用哪种方式提供AOP功能。
AdviceMode.PROXY表示用Spring自带的AOP功能,AdviceMode.ASPECTJ表示使用ASPECTJ提供AOP功能。
需要注意的是Spring自带的AOP功能不支持本地调用的代理功能,也就是说同一个类中的方法互相调用不会“触发”代理方法。
如果想让自调用触发代理,可以考虑使用ASPECTJ。
@FK
@Bean
public Date d1() {
return new Date() ;
}
@Bean
public Date d2() {
return new Date() ;
}
@Resource
@FK
private List dates = Collections.emptyList() ;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/**
* @Description: 动态多数据源
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map
@Configuration
public class TransactionConfig {
public final static String DEFAULT_TX = "defaultTx";
public final static String SECOND_TX = "secondTx";
@Bean(name=TransactionConfig.DEFAULT_TX)
@Primary
public DataSourceTransactionManager transaction(@Qualifier("firstDataSource")DataSource firstDataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(firstDataSource);
return dataSourceTransactionManager;
}
@Bean(name=TransactionConfig.SECOND_TX)
public DataSourceTransactionManager secondTransaction(@Qualifier("secondDataSource") DataSource secondDataScoure){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(secondDataScoure);
return dataSourceTransactionManager;
}
}