本文记录下通过注解动态配置数据源的实现方式,可以是不同的数据库(如读写分离),也可以是mycat代理的分表数据源。废话不多,上干货——
一、数据库配置文件(这里用的是阿波罗配置中心,也可以是application.yml文件)
#mysql本地数据源1
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.jdbc-url=jdbc:mysql://127.0.0.1:3306/mysqlDB1?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456#mysql本地数据源2
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.jdbc-url=jdbc:mysql://127.0.0.1:3306/mysqlDB2?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456#mycat本地数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.jdbc-url=jdbc:mysql://192.168.0.110:3306/mycatDB?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
二、java代码功能部分(根据自己的需求配置实现,不需要mycat分表的可以不配置mycat部分)
1、首先实现数据源配置
import com.xxx.xxx.aop.DataSourceNames;
import com.xxx.xxx.aop.DynamicDataSource;
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.util.*;
@Configuration
@Component
@MapperScan("com.datian.iot.mysql.mapper")
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource mysqlDataSource(){
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.mycat")
public DataSource mycatDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name = "dataSource")
@Primary
public DynamicDataSource dataSource(DataSource mysqlDataSource1, DataSource mysqlDataSource2, DataSource mycatDataSource) {
Map
2、定义数据源注解常量
public interface DataSourceNames {
String MYSQLDB1 = "mysqlDB1";
String MYSQLDB2 = "mysqlDB2";
String MYCATDB = "mycatDB";
}
3、定义数据源注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DataSource {
String dataSourceName() default DataSourceNames.MYSQLDB1;
}
4、实现数据源注解
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
@Aspect
@Order(0)
public class DataSourceSection {
@Pointcut("@annotation(com.datian.iot.aop.DataSource)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource ds = method.getAnnotation(DataSource.class);
if(ds == null){
DynamicDataSource.setDataSource(DataSourceNames.MYSQLDB1);
}else {
DynamicDataSource.setDataSource(ds.dataSourceName());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
}
5、动态数据源实现
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
public class DynamicDataSource extends AbstractRoutingDataSource {
// 用来保存数据源与获取数据源
private static final ThreadLocal contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map
三、测试部分
1、编写启动类(注意添加@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })屏蔽springboot的数据源自动配置)
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
@EnableScheduling
@EnableApolloConfig
@MapperScan("com.xxx.xxx.mysql.mapper*")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
2、常规测试
import com.xxx.xxx.mysql.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private TestService testService;
@PostMapping("manualOperation")
public List
import java.util.List;
import java.util.Map;
public interface TestService {
List
import com.xxx.xxx.aop.DataSource;
import com.xxx.xxx.aop.DataSourceNames;
import com.xxx.xxx.mysql.TestService;
import com.xxx.xxx.mysql.mapper.TestMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestMapper testMapper;
// 需要哪个数据源直接添加注解即可,不加默认用MYSQLDB1
@Override
@DataSource(dataSourceName = DataSourceNames.MYSQLDB2)
public List
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface TestMapper {
List
四、遇到的问题
1、数据库连接问题:(dataSource or dataSourceClassName or jdbcUrl is required.)MySQL版本不同,jdbc-url 和 driver-class-name 的写法不同,需要注意;
2、事务不生效:首先考虑MySQL引擎,InnoDB 引擎支持事务,而 MyISAM 引擎不支持事务,期次看下是否在配置数据源时忘记注入事务管理器。



