spring boot多数据源、读写分离( AOP动态)
项目地址
应用场景
读写分离,多数据源,主从库
具体实现
1、配置文件application.yml
##多数据源 datasource: #主库 master: jdbcUrl: jdbc:mysql://localhost:3306/pa_yqs_game?useUnicode=true&characterEncoding=utf-8 username: root password: root driver-class-name: com.mysql.jdbc.Driver #从库 slave: #并非url而是jdbcUrl(因为这个在获取数据源时一直报错,看了DataSource的属性才知道是jdbcUrl) jdbcUrl: jdbc:mysql://localhost:3306/data_count?useUnicode=true&characterEncoding=utf-8 username: root password: root driver-class-name: com.mysql.jdbc.Driver ##mybatis mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.*.domain.pojo check-config-location: true config-location: classpath:mybatis-config.xml
2、Application启动类
/** * **在最外侧,即包含所有子包 * @ClassName Application * @Description 入口,启动类 * @author lide * @date 2018年2月9日 下午2:47:04 */ @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @EnableTransactionManagement(order = 2) //设置事务执行顺序(需要在切换数据源之后,否则只走默认库) @MapperScan(basePackages = "com.example.*.domain.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
1. 需要设置事务(本质也是AOP)执行的顺序,否则事务的执行顺序高于后续的AOP,会导致动态切换数据源失效
2. exclude = {DataSourceAutoConfiguration.class}用于禁用掉默认的数据源获取方式,默认会读取配置文件的据源(spring.datasource.*)
3. MapperScan()指向的是mapper
3、代码实现
3.1 DataSourceType数据源枚举
public enum DataSourceType { // 主表 Master("master"), // 从表 Slave("slave"); private String name; private DataSourceType(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.2 数据源上下文JdbcContextHolder(ThreadLocal)
public class JdbcContextHolder { private final static ThreadLocal local = new ThreadLocal<>(); public static void putDataSource(String name) { local.set(name); } public static String getDataSource() { return local.get(); } }
3.3 AbstractRoutingDataSource实现类DynamicDataSource(关键)
AbstractRoutingDataSource抽象类知识,实现AOP动态切换的关键
AbstractRoutingDataSource中determineTargetDataSource()方法中获取数据源
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
根据determineCurrentLookupKey()得到Datasource,并且此方法是抽象方法,应用可以实现
2.resolvedDataSources的值根据targetDataSources所得
afterPropertiesSet()方法中(在@Bean所在方法执行完成后,会调用此方法):
Map.Entry
3.然后在xml中使用
4.利用自定义注解,AOP拦截动态的设置ThreadLocal的值
5.在DAO层与数据库建立连接时会根据ThreadLocal的key得到数据源
代码:getConnection()
determineTargetDataSource().getConnection();(determineTargetDataSource返回的是DataSource)
public class DynamicDataSource extends AbstractRoutingDataSource { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override protected Object determineCurrentLookupKey() { logger.info("数据源为{}",JdbcContextHolder.getDataSource()); return JdbcContextHolder.getDataSource(); } }
3.4 AOP切换数据源 DataSourceAspect
@Aspect @Order(1) //设置AOP执行顺序(需要在事务之前,否则事务只发生在默认库中) @Component public class DataSourceAspect { private Logger logger = LoggerFactory.getLogger(this.getClass()); //切点 @Pointcut("execution(* com.example.*.service..*.*(..)))") public void aspect() { } @Before("aspect()") private void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class classz = target.getClass(); Class[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz.getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(MyDataSource.class)) { MyDataSource data = m.getAnnotation(MyDataSource.class); JdbcContextHolder.putDataSource(data.value().getName()); logger.info("===============上下文赋值完成:{}",data.value().getName()); } } catch (Exception e) { e.printStackTrace(); } } }
3.5 自定义注解MyDataSource
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyDataSource { DataSourceType value() default DataSourceType.Master; //默认主表 }
3.6 数据源配置
注意@Primary标注多数据源,否则会产生实现类冲突。
@Primary和@Qualifier这两个注解的意思:
@Primary: 意思是在众多相同的bean中,优先使用用@Primary注解的bean.
@Qualifier : 这个注解则指定某个bean有没有资格进行注入。
@Configuration public class DataSourceConfig { @Bean(name = "master") @ConfigurationProperties(prefix = "datasource.master") public DataSource dataSource1() { System.out.println("主配"); return DataSourceBuilder.create().build(); } @Bean(name = "slave") @ConfigurationProperties(prefix = "datasource.slave") public DataSource dataSource2() { System.out.println("从配"); return DataSourceBuilder.create().build(); } @Bean(name="dynamicDataSource") @Primary //优先使用,多数据源 public DataSource dataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); DataSource master = dataSource1(); DataSource slave = dataSource2(); //设置默认数据源 dynamicDataSource.setDefaultTargetDataSource(master); //配置多数据源 Map map = new HashMap<>(); map.put(DataSourceType.Master.getName(), master); //key需要跟ThreadLocal中的值对应 map.put(DataSourceType.Slave.getName(), slave); dynamicDataSource.setTargetDataSources(map); return dynamicDataSource; } }

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
ActiveMQ进阶配置
配置web管理页面的安全认证 默认的web页面用户名密码admin:admin,非常不安全, 编辑jetty-realm.properties文件,(用户:密码,组) admin:admin123, admin user:user123, user 配置web管理页面的绑定IP和端口 编辑jetty.xml,查找WebConsolePort <bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start"> <!-- the default port number for the web console --> <property name="host" value="192.168.0.31"/> <property name="port" value="8161"/> </bean> 配置MQ连接的安全认证 编辑activemq.xml,在<broker>下加 ...
- 下一篇
【转】Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询
摘要: 出处 www.bysocket.com 「泥瓦匠BYSocket 」 运行环境:JDK 7 或 8,Maven 3.0+ 技术栈:SpringBoot 1.5+,ElasticSearch 2.3.2 本文提纲 一、ES 的使用场景 二、运行 springboot-elasticsearch 工程 三、springboot-elasticsearch 工程代码详解 推荐 - 「springboot-learning-example」开源项目,Fork 一下,多多 Pull Request~ spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 https://git.oschina.net/jeff1993/springboot-learning-example 一、ES 的使用场景 简单说,ElasticSearch(简称 ES)是搜索引擎,是结构化数据的分布式搜索引擎。 在《Elasticsearch 和插件 elasticsearch-head 安装详解》 和 《Elasticsearch 默认配置 IK 及 Java Ana...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Hadoop3单机部署,实现最简伪集群
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作