一、Springboot配置双数据源
在Spring Boot应用程序中配置多个数据源是很常见的需求。由于Spring Boot的自动配置机制,使得我们可以轻松优雅的实现多数据源配置和切换。 若要配置双数据源,则需要使用Spring Boot的自动装配机制执行以下操作:
1. 确保我们的应用程序中依赖了Spring Boot的MyBatis Starter,这将为MyBatis集成提供必要的依赖关系和自动配置。在pom.xml文件中添加以下依赖:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency>
2. 在application.properties中配置双数据源的各项信息:
# primary datasource spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db spring.datasource.primary.username=dbuser spring.datasource.primary.password=dbpassword spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver # secondary datasource spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db spring.datasource.secondary.username=dbuser spring.datasource.secondary.password=dbpassword spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
3. 创建主数据源和次数据源的数据源类:
@Configuration @MapperScan(basePackages = "com.example.demo.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate") public class PrimaryDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; @Bean(name = "primaryDataSource") @Primary public DataSource primaryDataSource() { return dataSourceProperties.initializeDataSourceBuilder().build(); } @Bean(name = "primarySqlSessionFactory") @Primary public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource primaryDataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(primaryDataSource); return sessionFactory.getObject(); } @Bean(name = "primaryTransactionManager") @Primary public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource primaryDataSource) { return new DataSourceTransactionManager(primaryDataSource); } @Bean(name = "primarySqlSessionTemplate") @Primary public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory primarySqlSessionFactory) { return new SqlSessionTemplate(primarySqlSessionFactory); } } @Configuration @MapperScan(basePackages = "com.example.demo.mapper.secondary", sqlSessionTemplateRef = "secondarySqlSessionTemplate") public class SecondaryDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; @Bean(name = "secondaryDataSource") public DataSource secondaryDataSource() { return dataSourceProperties.initializeDataSourceBuilder().build(); } @Bean(name = "secondarySqlSessionFactory") public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(secondaryDataSource); return sessionFactory.getObject(); } @Bean(name = "secondaryTransactionManager") public DataSourceTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) { return new DataSourceTransactionManager(secondaryDataSource); } @Bean(name = "secondarySqlSessionTemplate") public SqlSessionTemplate secondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory") SqlSessionFactory secondarySqlSessionFactory) { return new SqlSessionTemplate(secondarySqlSessionFactory); } }
4. 创建controller并在其中注入主数据源的mapper和次数据源的mapper
@RestController @RequestMapping("/users") public class UserController { @Autowired private PrimaryUserMapper primaryUserMapper; @Autowired private SecondaryUserMapper secondaryUserMapper; @GetMapping("/primary/list") public ListgetPrimaryUsers() { return primaryUserMapper.getAll(); } @GetMapping("/secondary/list") public List getSecondaryUsers() { return secondaryUserMapper.getAll(); } }
5. 启动应用并测试多数据源的配置是否正确。
二、Mybatis多数据源配置SpringBoot
当使用Mybatis作为数据持久层框架时,需要按以下步骤在SpringBoot中配置多数据源:
1. 在pom.xml文件中添加以下依赖关系:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency>
2. 在application.properties或application.yml文件中配置数据源信息:
# primary datasource spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db spring.datasource.primary.username=dbuser spring.datasource.primary.password=dbpassword spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver # secondary datasource spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db spring.datasource.secondary.username=dbuser spring.datasource.secondary.password=dbpassword spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
3. 创建数据源类、SqlSessionFactory、SqlSessionTemplate和TransactionManager:
@Configuration @MapperScan(basePackages = "com.example.demo.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate") public class PrimaryDataSourceConfig { @Autowired private DataSource primaryDataSource; @Bean(name = "primarySqlSessionFactory") @Primary public SqlSessionFactory primarySqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(primaryDataSource); return sessionFactory.getObject(); } @Bean(name = "primaryTransactionManager") @Primary public DataSourceTransactionManager primaryTransactionManager() { return new DataSourceTransactionManager(primaryDataSource); } @Bean(name = "primarySqlSessionTemplate") @Primary public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory primarySqlSessionFactory) { return new SqlSessionTemplate(primarySqlSessionFactory); } } @Configuration @MapperScan(basePackages = "com.example.demo.mapper.secondary", sqlSessionTemplateRef = "secondarySqlSessionTemplate") public class SecondaryDataSourceConfig { @Autowired private DataSource secondaryDataSource; @Bean(name = "secondarySqlSessionFactory") public SqlSessionFactory secondarySqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(secondaryDataSource); return sessionFactory.getObject(); } @Bean(name = "secondaryTransactionManager") public DataSourceTransactionManager secondaryTransactionManager() { return new DataSourceTransactionManager(secondaryDataSource); } @Bean(name = "secondarySqlSessionTemplate") public SqlSessionTemplate secondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory") SqlSessionFactory secondarySqlSessionFactory) { return new SqlSessionTemplate(secondarySqlSessionFactory); } }
4. 创建主数据源mapper和次数据源mapper,并在其中分别使用@Qualifier注解注入对应的数据源的SqlSessionTemplate。
5. 对于需要使用次数据源的Service或Dao类中,使用@Qualifier注解指定对应的SqlSessionTemplate。
6. 启动应用并测试多数据源的配置是否正确。
三、Springboot动态配置数据源
无论是配置双数据源还是多数据源,都需要在application.properties或application.yml文件中预先配置好数据源信息。然而,在生产环境中,可能需要根据用户的访问请求,动态选择不同的数据源。因此,需要在运行时动态配置数据源,具体步骤如下:
1. 在pom.xml文件中添加以下依赖关系:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
2. 配置与数据源相关的bean:
@Configuration public class DynamicDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; private final MapdataSources = new ConcurrentHashMap<>(); @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(dataSourceProperties.getDriverClassName()); dataSource.setUrl(dataSourceProperties.getUrl()); dataSource.setUsername(dataSourceProperties.getUsername()); dataSource.setPassword(dataSourceProperties.getPassword()); return new DynamicRoutingDataSource(dataSource); } @Bean public DataSourceTransactionManager dataSourceTransactionManager() { return new DataSourceTransactionManager(dataSource()); } @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); return sessionFactory.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate() throws Exception { return new SqlSessionTemplate(sqlSessionFactory()); } }
3. 创建动态数据源类DynamicRoutingDataSource和动态数据源上下文ThreadLocal:
public class DynamicRoutingDataSource extends AbstractRoutingDataSource { public DynamicRoutingDataSource(DataSource defaultTargetDataSource) { super.setDefaultTargetDataSource(defaultTargetDataSource); } @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceKey(); } } public class DynamicDataSourceContextHolder { private static final ThreadLocalCONTEXT_HOLDER = new ThreadLocal<>(); public static void setDataSourceKey(String key) { CONTEXT_HOLDER.set(key); } public static String getDataSourceKey() { return CONTEXT_HOLDER.get(); } public static void clearDataSourceKey() { CONTEXT_HOLDER.remove(); } }
4. 创建DynamicDataSourceAspect类,在函数执行前获取数据源的key并设置到DynamicDataSourceContextHolder中,函数执行完毕后清除DynamicDataSourceContextHolder。
@Aspect @Component public class DynamicDataSourceAspect { private final Logger logger = LoggerFactory.getLogger(getClass()); @Before("execution(* com.example.demo.service.*.*(..))") public void before(JoinPoint point) { String dataSourceKey = point.getSignature().getName().contains("primary") ? "primary" : "secondary"; DynamicDataSourceContextHolder.setDataSourceKey(dataSourceKey); logger.info(String.format("设置数据源为 %s", dataSourceKey)); } @After("execution(* com.example.demo.service.*.*(..))") public void after(JoinPoint point) { DynamicDataSourceContextHolder.clearDataSourceKey(); logger.info("清除数据源"); } }
5. 在需要多数据源的Service实现类中,添加以下注解,这将激活DynamicDataSourceAspect,从而动态设置数据源:
@Service public class UserServiceImpl implements UserService { @Autowired private PrimaryUserMapper primaryUserMapper; @Autowired private SecondaryUserMapper secondaryUserMapper; @Primary @DataSource(key = "primary") public ListgetAllPrimaryUsers() { return primaryUserMapper.getAll(); } @DataSource(key = "secondary") public List getAllSecondaryUsers() { return secondaryUserMapper.getAll(); } // ... }
四、Springboot配置多数据源Druid
如果需要使用连接池,可以选择使用阿里巴巴的Druid。具体步骤如下:
1. 在pom.xml文件中添加以下依赖关系:
<dependency> <groupId>com.alibaba <artifactId>druid-spring-boot-starter <version>1.2.5 </dependency>
2. 在application.properties或application.yml文件中配置DruidDataSource的各项信息:
# primary datasource spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true spring.datasource.primary.username=dbuser spring.datasource.primary.password=dbpassword spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource # druid specific config spring.datasource.primary.initial-size=0 spring.datasource.primary.min-idle=0 spring.datasource.primary.max-active=20 spring.datasource.primary.max-wait=-1 spring.datasource.primary.time-between-eviction-runs-millis=60000 spring.datasource.primary.min-evictable-idle-time-millis=300000 spring.datasource.primary.validation-query=SELECT 1 FROM DUAL spring.datasource.primary.test-while-idle=true spring.datasource.primary.test-on-borrow=false spring.datasource.primary.test-on-return=false spring.datasource.primary.pool-prepared-statements=true spring.datasource.primary.max-pool-prepared-statement-per-connection-size=20 spring.datasource.primary.filters=stat,wall,log4j spring.datasource.primary.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # secondary datasource spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true spring.datasource.secondary.username=dbuser spring.datasource.secondary.password=dbpassword spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver spring.datasource.secondary.type=com.alibaba.druid.pool.DruidDataSource # druid specific config spring.datasource.secondary.initial-size=0 spring.datasource.secondary.min-idle=0 spring.datasource.secondary.max-active=20 spring.datasource.secondary.max-wait=-1 spring.datasource.secondary.time-between-eviction-runs-millis=600