Git Product home page Git Product logo

mybatis-r2dbc's Introduction

MyBatis R2DBC Adapter

将MyBatis Reactive化,将底层的JDBC替换为R2DBC,从而实现全面异步化,提升数据库访问性能。

MyBatis R2DBC工作原理

MyBatis R2DBC Structure

  • 对数据CRUD操作SqlSession接口进行Reactive化,对于R2DBC适配来说为ReactiveSqlSession
  • Mapper接口Reactive化,将函数的类型从对象和List调整为Mono和Flux
  • SQL的执行器调整为R2DBC的接口,这里我们不需要类似MyBatis的Executor机制,Reactive框架为R2DBC提供了执行调度功能
  • 结果处理和映射:R2DBC Data Types 支持,你也可以扩展R2DBCTypeHandler添加自定义类型。MyBatis R2DBC增加了JDBC Types的支持,主要是考虑兼容性。

如何使用?

和MyBatis的使用流程一样,如下:

// construct MyBatis Configuration
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(this.getClass().getResourceAsStream("/mybatis-config.xml"));
Configuration configuration = xmlConfigBuilder.parse();

// construct Reactive SQL Session Factory
ReactiveSqlSessionFactory reactiveSqlSessionFactory = new DefaultReactiveSqlSessionFactory(configuration);
ReactiveSqlSession reactiveSqlSession = reactiveSqlSessionFactory.openSession();

// construct Reactive Mapper interface
UserReactiveMapper userMapper = reactiveSqlSession.getMapper(UserReactiveMapper.class);

特性

  • 兼容MyBatis 3的配置和编程接口,主要是Mapper接口和SQL的XML配置方式
  • XxxMapper 调整为 Reactive 接口
  • Metrics support: 每一个statement的metrics都可以被记录
  • R2DBC Pool支持
  • Dynamic SQL支持

核心工作

  • 将底层的JDBC调整为R2DBC
  • 兼容 Spring Data R2DBC
  • r2dbc-mysql的兼容性测试
  • TypeHandler支持

主要调整点

  • Reactive SqlSessionFactory
  • Reactive SqlSession
  • Reactive Mapper interface

R2DBC-MyBatis支持的数据类型

R2DBC有标准的Data Types支持,可以在 https://r2dbc.io/spec/0.8.1.RELEASE/spec/html/#datatypes 进行查阅

考虑到MyBatis JDBC支持的类型,以下的类型也是被支持的:

  • Java Date: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp

R2DBC Transaction

Please use R2dbcTransactionManager from Spring Data R2DBC

MySQL的R2DBC Driver

从目前开发的情况来看,可能MariaDB R2DBC更具有前景一些。

TypeHandler支持

MyBatis针对resultMap的result有一个typeHandler的设置,可以进行Java对象字段和数据库表的column直接进行值转换。 在MyBatis R2DBC中我们保留这一特性。 由于R2DBC和JDBC的API完全不同,所以新增了一个R2DBCTypeHandler接口,代码如下:

public interface R2DBCTypeHandler<T> {

    void setParameter(Statement statement, int i, T parameter, JdbcType jdbcType) throws R2dbcException;

    T getResult(Row row, String columnName, RowMetadata rowMetadata) throws R2dbcException;

    T getResult(Row row, int columnIndex, RowMetadata rowMetadata) throws R2dbcException;

    Class<?> getType();
}

但是考虑到实际的MyBatis的配置验证,新建的TypeHandler实现需要同时继承TypeHandler和R2DBCTypeHandler接口,同时也保证在JDBC和R2DBC同时生效。

你可以参考 org.apache.ibatis.r2dbc.type 开发包下的type handler进行编写,同时JDBC的时间类型的兼容,也是通过type handler完成的。

Java Enum type handler和MyBatis处理机制类似,只是类名调整到R2DBC下的EnumOrdinalTypeHandler,代码如下:

 <typeHandlers>
        <!-- Enum ordinal type handler-->
        <typeHandler handler="org.apache.ibatis.r2dbc.type.EnumOrdinalTypeHandler"
                     javaType="java.math.RoundingMode"/>
 </typeHandlers>

注意: @MappedJdbcTypes类型的TypeHandler不支持

Transaction支持

Reactive Transaction 支持 https://spring.io/blog/2019/05/16/reactive-transactions-with-spring

Spring的R2dbcTransactionManager是基于R2DBC的ConnectionFactory,所以我们不需要进行什么配置,基本代码如下:

public class R2dbcTransactionManagerAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(ReactiveTransactionManager.class)
	public R2dbcTransactionManager connectionFactoryTransactionManager(ConnectionFactory connectionFactory) {
		return new R2dbcTransactionManager(connectionFactory);
	}

}

如果是基于R2DBC Pool,R2dbcTransactionManager就是基于ConnectionPool的,当然ConnectionPool就是继承自ConnectionFactory的。

配置参数

和R2DBC相关的配置参数,主要是通过MyBatis的mybatis-config.xml文件中的properties配置完成的,如下:

<configuration>
    <properties>
        <property name="metrics.enabled" value="true"/>
        <property name="r2dbc.pool.initial-size" value="1"/>
        <property name="r2dbc.pool.max-size" value="10"/>
        <!-- max idle time, the unit is Minute-->
        <property name="r2dbc.pool.max-idle-time" value="5"/>
    </properties>
</configuration>

R2DBC MyBatis的不同点

背后的原因其实主要是JDBC和R2DBC的区别,我们都知道JDBC同步Block的,所以我们需要有连接池DataSource,防止应为JDBC的等待造成Thread的堵塞。

SqlSession ReactiveSqlSession

MyBatis的一个核心是SqlSession,但是两者的设计还有很大的区别的:

  • MyBatis的原生SqlSession是基于JDBC,是Block的,所以存在SessionHolder的感念,如commit,rollback, close等API
  • ReactiveSqlSession则是 异步 + 单例(Singleton)的,和Spring的WebClient,Spring Data R2DBC的DatabaseClient一样的,只是名字还是叫做Session,和MyBatis一致而已。

DataSource和R2DBC Pool

JDBC使用连接池这个大家都明白, 通过增加连接数减少因为JDBC Connection等待的结果造成的block,不然应用整体的性能下降的非常快。 在R2DBC中也有Connection Pool的概念,其主要是兼容传统数据库同步协议,如MySQL,解释如下:

Traditionally, many MySQL drivers used a synchronous approach when executing SQL statements. This meant that operations such as opening connections and executing queries were blocked until completion, which could take a long time. To allow for parallel execution, a developer had to write a multithreaded application. Any MySQL client that supports the X Protocol can provide asynchronous execution, either using callbacks, Promises, or by explicitly waiting on a specific result at the moment in time when it is actually needed.

如果数据库通讯协议是全部异步的,那么是没有必要介入Connection Pool的。 如mariadb-connector-r2dbc的实现中就有:

allowPipelining: Permit to send queries to server without waiting for previous query to finish

如果allowPipelining为false,这个时候,出于性能的考虑,你还是需要介入R2DBC Pool来提升应用性能。

Pipelining versus Parallel Query Execution请参考: https://www.percona.com/blog/2016/07/06/pipelining-versus-parallel-query-execution-with-mysql-5-7-x-plugin/

Cache特性

对于Reactive来说,默认就包含了cache特性,也就是你可以调用 Mono.cache() 或 Flux.cache 就可以缓存响应的结果集,然后提供给后续的订阅者消费。

对应MyBatis来说,cache也并复杂,Cache也是基于Mapper的,我们只需要基于paramObject缓存对应的Mono或者Flux对象就可以。

 Mono<String> user = Mono.defer(() -> {
            // r2dbc operation
            return r2dbcResult;
        }).cache(Duration.ofSeconds(2));

但是,这个只是基于内存的对象缓存,如果是分布式的,上述机制不能工作,这涉及到对象序列化和反序列化机制的机制。

至于选择哪一种,这个可能要根据实际的缓存类型进行决定。

spring-boot-starter-data-r2dbc整合

如果你项目中已经包含spring-boot-starter-data-r2dbc,那么你可以完全使用Spring Boot提供的R2DBC的ConnectionFactory bean完成数据库连接相关的任务。

@Bean
public ReactiveSqlSessionFactory reactiveSqlSessionFactory(ConnectionFactory r2dbcConnectionFactory)  {
  XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(this.getClass().getResourceAsStream("/mybatis-config.xml"));
  Configuration configuration = xmlConfigBuilder.parse();
  return new DefaultReactiveSqlSessionFactory(configuration, r2dbcConnectionFactory);
}

不支持的特性

  • MyBatis Plugin机制: org.apache.ibatis.plugin.Interceptor
  • 不支持配置文件中声明Reactive Mapper接口,R2DBC需要额外的API支持
<mappers>
  <mapper class="org.mybatis.builder.AuthorReactiveMapper"/>
</mappers>

参考

mybatis-r2dbc's People

Contributors

0xflotus avatar chenggangpro avatar linux-china avatar naah69 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mybatis-r2dbc's Issues

整合 Mybatis 源码,整合spring-r2dbc

适配了Mybatis源码,麻烦大佬看一下是否可以可用。由于变更的文件较多,就没有PR。如果可以的话,会重新提PR过来。

地址 :https://github.com/chenggangpro/reactive-mybatis-support
分支:main

只进行了简单功能性测试(见测试用例)
适配过程中删除了Mybatis源码中一下未使用的类和代码,可能有多余代码没有删除干净


已测试的功能: (MySQL)

1 . 事物操作
2 . 参数解析,parameterMap
3 . resultType,resultMap,一对一,一对多结果集嵌套映射(<association/>/<collection/>
4 . 返回自增主键

支持的功能:
  • 1 . 参数解析
  • 2 . Result解析(一对一,一对多等)
  • 3 . 事物操作
  • 4 . 通过适配器扩展r2dbc数据类型
不支持的功能
  • 1 . 嵌套查询(nested query),在一个mapper方法上执行多条SQL
  • 2 . 通过嵌套查询(nested query)返回主键
  • 3 . 多个 ResultSet,没有测试存储过程
  • 4 . 多ResultMap(只支持一个ResultMap或者嵌套的ResultMap)
  • 5 . mybatis-plugin
  • 6 . InputStream数据类型等阻塞类型

springboot无缝整合扩展

你好,最近新开项目其中使用了webflux+mybatis-r2dbc,对mybatis-r2dbc与springboot做了下无缝整合扩展,主要如下:
1、增加mybatis-r2dbc启动标签,mapper类可以通过@Autowired 标签自动注入。
2、增加事务管理标签,通过对方法标记为@R2dbcTransactional后,自动进行事务管理。
3、增加application.yml配置方式,可以不用再配置mybatis-config.xml文件。
4、修改了若干使用过程出现的bug。
5、您看,我如何把代码提交给您,进行审查下。
谢谢。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.