使用aop方式来实现功能
-
获取依赖的jar包,maven配置文件。使用MyBatis 管理数据库
<parent> <groupId> org.springframework.boot </groupId> <artifactId>spring-boot-starter-parent </artifactId> <version> 2.0.5.RELEASE </version> </parent> <dependencies> <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter </artifactId> </dependency> <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-web </artifactId> </dependency> <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-test </artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-aop </artifactId> </dependency> </dependencies>
-
装配数据源,两个以上
###datasource01 spring.datasource.test1.jdbc-url=jdbc:mysql:///test1 spring.datasource.test1.username=root spring.datasource.test1.password=root spring.datasource.test1.driver-class-name=com.mysql.jdbc.Driver ###datasource02 spring.datasource.test2.jdbc-url=jdbc:mysql:///test2 spring.datasource.test2.username=root spring.datasource.test2.password=root spring.datasource.test2.driver-class-name=com.mysql.jdbc.Driver
-
多数据源配置类
@Configuration public class DataSourceConfig { //数据源1 @Bean(name="datasource1") @ConfigurationProperties(prefix="spring.datasource.test1") public DataSource dataSource1(){ return DataSourceBuilder.create().build(); } //数据源2 @Bean(name="datasource2") @ConfigurationProperties(prefix="spring.datasource.test2") public DataSource dataSource2(){ return DataSourceBuilder.create().build(); } //配置动态数据源,通过aop切换数据源 @Primary @Bean(name="dynamicDataSource") public DataSource dynamicDataSource(){ DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setDefaultTargetDataSource(dataSource1()); Map<Object, Object> dbMap = new HashMap<Object, Object>(); dbMap.put("datasource1", dataSource1()); dbMap.put("datasource2", dataSource2()); dynamicDataSource.setTargetDataSources(dbMap); return dynamicDataSource; } //配置Transaction,统一管理 @Bean(name="transactionManager") public PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(dynamicDataSource()); } }
-
保存当前数据源
public class DataSourceContextHolder { //默认的数据源 public static final String DEFAULT_DB = "datasource1"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); //设置数据源 public static void setDB(String dbType){ System.out.println("切换到---" + dbType + "---数据源"); contextHolder.set(dbType); } //获取数据源 public static String getDB(){ return (contextHolder.get()); } //清除数据源 public static void clearDB(){ contextHolder.remove(); } }
-
当前数据源
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { System.out.println("数据源为---" + DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); } }
-
自定义注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface DataSource { String value() default "datasource1"; }
-
aop管理动态切换数据源
@Aspect @Component @Order(-10) //@Order 值越小,优先级越高 public class DynamicDataSourceAspect { @SuppressWarnings("rawtypes") @Before("@annotation(DataSource)") public void before(JoinPoint point){ //获取当前访问的类名 Class<?> className = point.getTarget().getClass(); //获取当前访问的方法名 String methodName = point.getSignature().getName(); //获取方法的参数类型 Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes(); //默认数据源 String dataSource = DataSourceContextHolder.DEFAULT_DB; try { //获取访问的方法对象 Method method = className.getMethod(methodName, argClass); //判断是否存在@DataSource注解 if(method.isAnnotationPresent(DataSource.class)){ DataSource annotation = method.getAnnotation(DataSource.class); //获取注解中指定的数据源 dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } //切换到指定的数据源 DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DataSource)") public void after(JoinPoint point){ DataSourceContextHolder.clearDB(); } }
切面处要添加注解@Order(-10),如果不使用,在使用@Transaction注解的时候,会使数据源的动态切换无效,始终只使用默认的数据源
8. 实体层
@Data
@ToString
public class User {
private Integer id;
private String name;
private Integer age;
}
这里我使用了Lombok插件,如果没有装插件的话,就把注释去掉,乖乖写getter,setter方法,建议可以去装一个
-
dao层
public interface UserMapper { @Select("SELECT * FROM USER WHERE NAME = #{name}") public User findByName(@Param("name") String name); @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})") int insert(@Param("name") String name, @Param("age") Integer age); }
-
service层
@Service
public class UserService {
@Autowired
private UserMapper mapper;
@DataSource("datasource1")
@Transactional
public int insertUser1(String name, Integer age){
int result = mapper.insert(name, age);
int i = 1 / age;
return result;
}
@DataSource("datasource2")
@Transactional
public int insertUser2(String name, Integer age){
int result = mapper.insert(name, age);
int i = 1 / age;
return result;
}
}
- controller层
@RestController
public class DataSourceController {
@Autowired
private UserService userService;
@RequestMapping("/insert1")
public Integer insert01(String name, Integer age){
return userService.insertUser1(name, age);
}
@RequestMapping("/insert2")
public Integer insert02(String name, Integer age){
return userService.insertUser2(name, age);
}
}
- 启动类
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
@MapperScan(basePackages="com.ma.springboot.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
这里要在SpringBootApplication注解中标明exclude=DataSourceAutoConfiguration.class。不然的话,SpringBoot自动装载的事务会让项目无法启动