支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

这篇文章主要讲解了“支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么”吧!

为王益等地区用户提供了全套网页设计制作服务,及王益网站建设行业解决方案。主营业务为成都网站设计、做网站、王益网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!

支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

项目更名

在easymulti-datasource-spring-boot-starter之后笔者又开发了hotkit-r2dbc,这两个项目都支持动态数据源切换,前者支持mybatis框架,后者支持响应式编程spring-data-r2dbc框架,既然都是ORM框架,不如合并到一个项目中维护。

GitHub上原easymulti-datasource-spring-boot-starter项目已更名为easymulti-datasource,而原easymulti-datasource-spring-boot-starter模块已经更名为easymulti-datasource-mybatis,版本号从3.0.1开始。新版本增加了easymulti-datasource-r2dbc(也就是原hotkit-r2dbc)。

项目背景

多数据源动态切换似乎已经成了微服务的标配,做过那么多项目发现每个项目都要配一个动态数据源,都要写一个切面去实现动态切换,因此,我将这些繁琐的配置封装为starter,拿来即用。

easymulti-datasource两个模块:

  • easymulti-datasource-mybatis(原easymulti-datasource-spring-boot-starter)

  • easymulti-datasource-r2dbc(原hotkit-r2dbc)

easymulti-datasource-mybatis

mybatis版多数据源框架,提供声明式和编程式动态切换数据源功能。

easymulti-datasource-mybatis自动整合了mybatis-plus,提供两种动态多数据源模式,分别是主从数据源模式、非主从的多数据源模式,每个数据源使用独立的连接池配置,可针对每个数据源单独配置连接池。

支持多数据源动态切换并不是easymulti-datasource-mybatis框架的最大亮点,easymulti-datasource-mybatis区别于其它动态数据源切换框架的主要特色如下:

支持监听SQL,监听修改某个表的某些字段的sql,用于实现埋点事件;

支持事务状态监听、注册事务监听器,用于在事务回滚/提交时再完成一些后台操作;

详细使用可参见wiki。

支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

依赖配置

maven中使用:

     com.github.wujiuye     easymulti-datasource-mybatis     ${version} 

旧版本为:

     com.github.wujiuye     easymulti-datasource-spring-boot-starter     ${version} 

版本选择注意事项说明如下图所示。

支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

动态切换数据源

  • 使用注解切换数据源:@EasyMutiDataSource;

  • 使用API切换数据源:DataSourceContextHolder#setDataSource。

AOP中注册事务监听器

在application配置文件中打开追踪事务方法调用链路的开关,配置如下。

## 监控事务方法调用链路 easymuti:   transaction:     open-chain: true

定义切面,拦截Mapper方法,在环绕方法中实现更新缓存的逻辑,代码如下。

支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么

  • TransactionInvokeContext.currentExistTransaction:判断当前调用链路上是否存在事务;

  • TransactionInvokeContext.addCurrentTransactionMethodPopListener:给当前事务绑定一个监听器(PopTransactionListener),当事务提交或者回滚时监听器被调用。

如上代码所示,首先是判断当前调用链路上是否存在事务,如果存在,则给当前事务注入一个监听器,由监听器完成缓存更新逻辑,如果不存在事务,在目标方法执行完成后且无异常抛出时执行更新缓存逻辑。

监听SQL

easymulti-datasource-mybatis支持sql埋点监听功能,并且支持监听事务状态,如果当前sql执行存在事务中,则会在事务提交后才会回调sql监听者。

第一步:启用sql埋点监听功能,并且启用事务调用链路追踪功能。

easymuti:    transaction:      open-chain: true   sql-watcher:     enable: true

第二步:编写观察者,可以有n多个,并且多个观察者也可观察同一个表、甚至相同字段。

@Component @Slf4j public class TestTableFieldObserver implements TableFieldObserver , InitializingBean {      @Override     public Set observeMetadatas() {        // 在这里注册要监听哪些表的哪些字段     }      /**      * 监听到sql时被同步调用      *      * @param commandType 事件类型      * @param matchResult 匹配的ITEM      * @return 返回异步消费者      */     @Override     public AsyncConsumer observe(CommandType commandType, MatchItem matchResult) {         // 同步消费         // 这里是sql执行之前,可在sql执行之前做一些事情,比如新旧数据的对比,这里查出旧数据          // 异步消费,再sql执行完成时,或者在事务方法执行完成时(如果存在事务),完成指:正常执行完成 or 方法异常退出         return throwable -> {             // sql执行抛出异常不处理             if (throwable != null) {                 return;             }             // 消费事件             // ....         };     }  }

observe方法在监听到sql时被同步调用,该方法返回的AsyncConsumer则在事务提交后被回调调用,如果事务回滚了则不会被调用。

如果调用链路上出现多个事务,那么根据事务的传播机制,只在当前方法所在事务提交时才会回调注册在该事务上的所有AsyncConsumer。

easymulti-datasource-r2dbc

spring-data-r2dbc版多数据源组件,用于响应式编程。

easymulti-datasource-r2dbc为spring-data-r2dbc实现动态路由接口,为反应式编程提供声明式和编程式多数据源动态切换提供支持。同样支持两种多数据源模式,覆盖常见的多数据源使用场景,分别是主从模式和Cluster模式,Cluster模式支持最多配置3个数据源,而主从模式支持一主一从。

添加依赖与配置数据源

使用easymulti-datasource-r2dbc后,无需再在项目中添加spring-boot-starter-data-r2dbc的依赖,也不需要添加spring-data-r2dbc的依赖。

easymulti-datasource-r2dbc版本号对应spring-data-r2dbc的版本号:

easymulti-datasource-r2dbcspring-data-r2dbc
3.0.1-RELEASE1.1.0.RELEASE

在项目中添加easymulti-datasource-r2dbc的依赖,如下。

     com.github.wujiuye     easymulti-datasource-r2dbc     ${version} 

此时,只需要额外添加用到的数据库类型对应的驱动依赖即可,例如,添加MySQL的r2dbc驱动。

     dev.miku     r2dbc-mysql     0.8.2.RELEASE 

如果使用主从模式,则使用如下配置。

easymuti:   database:     r2dbc:       master-slave-mode:         master:           url: r2dbc:mysql://127.0.0.1:3306/r2dbc_stu           username: root           password:           pool:             max-size: 5             idel-timeout: 60         slave:           url: r2dbc:mysql://127.0.0.1:3306/r2dbc_stu           username: root           password:           pool:             max-size: 5             idel-timeout: 60

master会被设置为默认使用的数据源,slave有则配置,没有也可以为空。虽然slave允许为空,但如果真的不需要多数据源,也是没有必要使用easymulti-datasource-r2dbc的。

如果使用Cluster模式,则使用如下配置。

easymuti:   database:     r2dbc:       cluster-mode:         first:           url: r2dbc:mysql://127.0.0.1:3306/r2dbc_stu           username: root           password:           pool:             max-size: 5             idel-timeout: 60         second:           url: r2dbc:mysql://127.0.0.1:3306/r2dbc_stu           username: root           password:           pool:             max-size: 5             idel-timeout: 60         third:           url: r2dbc:mysql://127.0.0.1:3306/r2dbc_stu           username: root           password:           pool:             max-size: 5             idel-timeout: 60

其中first会被设置为默认使用的数据源,second与third可以为空。

声明式动态切换数据源

声明式动态切换数据源即使用注解方式动态切换数据源,只需要在spring  bean的public方法或者类上添加@R2dbcDataBase注解,将注解的value属性指定为使用的数据源。

示例代码如下。

@Service public class PersonService {      @Resource     private PersonRepository personRepository;        // 方法返回值类型为Mono测试     @R2dbcDataBase(MasterSlaveMode.Master)     @Transactional(rollbackFor = Throwable.class)     public Mono addPerson(Person... persons) {         Mono txOp = null;         for (Person person : persons) {             if (txOp == null) {                 txOp = personRepository.insertPerson(person.getId(), person.getName(), person.getAge());             } else {                 txOp = txOp.then(personRepository.insertPerson(person.getId(), person.getName(), person.getAge()));             }         }         return txOp;     }      // 方法返回值类型为Flux测试     @R2dbcDataBase(MasterSlaveMode.Master)     @Transactional(rollbackFor = Throwable.class)     public Flux addPersons(Flux persons) {         return persons.flatMap(person -> personRepository.insertPerson(person.getId(), person.getName(), person.getAge()));     }  }
  • 如果是主从模式,@R2dbcDataBase注解的value属性可选值参见MasterSlaveMode接口声明的常量;

  • 如果是Cluster模式,@R2dbcDataBase注解的value属性可选值参见ClusterMode接口声明的常量;

编程式动态切换数据源

声明式切换数据源的实现是依赖编程式切换数据源实现的,因此,我们也可以直接编写代码切换数据源,而不需要将方法改为public暴露出去。

只需要调用EasyMutiR2dbcRoutingConnectionFactory提供的静态方法putDataSource为Context写入使用的数据源,代码如下。

public class RoutingTest extends SupporSpringBootTest {      @Resource     private DatabaseClient client;     @Resource     private ReactiveTransactionManager reactiveTransactionManager;      @Test     public void test() throws InterruptedException {         TransactionalOperator operator = TransactionalOperator.create(reactiveTransactionManager);         Mono atomicOperation = client.execute("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")                 .bind("id", "joe")                 .bind("name", "Joe")                 .bind("age", 34)                 .fetch().rowsUpdated()                 .then(client.execute("INSERT INTO person (id, name) VALUES(:id, :name)")                         .bind("id", "joe")                         .bind("name", "Joe")                         .fetch().rowsUpdated())                 .then();         // 包装事务         Mono txOperation = operator.transactional(atomicOperation);         // 包装切换数据源         EasyMutiR2dbcRoutingConnectionFactory.putDataSource(txOperation, MasterSlaveMode.Slave).subscribe();         TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);     }  }

需要注意,如果需要使用事务,必须先调用TransactionalOperator对象的transactional方法,再调用EasyMutiR2dbcRoutingConnectionFactory的putDataSource方法。

感谢各位的阅读,以上就是“支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么”的内容了,经过本文的学习后,相信大家对支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!


分享标题:支持监听SQL、感知事务状态、回溯数据源的动态数据源框架是什么
文章URL:http://scjbc.cn/article/ppdhdp.html

其他资讯