前言
- 怎样在Java的JDBC层提供额外的服务,源码是怎样实现的?
- 本篇文章首先梳理整个注册以及执行流程,发现Sharding-JDBC按照如下步骤提供服务
2.1 Sharding-JDBC根据配置生成数据源ShardingSphereDataSource
2.2 根据数据源获取连接ShardingSphereConnection
2.3 通过连接将sql封装成ShardingSpherePreparedStatement
2.4 委托ShardingSpherePreparedStatement执行update操作
环境搭建
- 下载shardingsphere的源码
- 切换到最新分支:5.1.0
- 编译打包(会生成相关的类)
- 参考issue修复方式对example的pom文件进行修改
4.1 改动的点参考提交记录 - 安装mysql-server,创建两个库:demo_ds_0、demo_ds_1
- 启动example的sharding-spring-boot-mybatis-example模块的ShardingSpringBootMybatisExample
6.1 结果展示:demo_ds_0、demo_ds_1两个库都新建了t_address表以及新增了10条记录
6.2 Sharding-JDBC是怎样实现的?很神奇
集成Sharding-JDBC
- 引入mybatis以及shardingsphere-jdbc的starter包
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency>
- 配置多数据源以及规则
// 多数据源 spring.shardingsphere.datasource.names=ds-0,ds-1 spring.shardingsphere.datasource.ds-0.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 spring.shardingsphere.datasource.ds-0.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds-0.driver-class-name=com.mysql.jdbc.Driver spring.shardingsphere.datasource.ds-0.username=root spring.shardingsphere.datasource.ds-0.password= spring.shardingsphere.datasource.ds-1.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 spring.shardingsphere.datasource.ds-1.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds-1.driver-class-name=com.mysql.jdbc.Driver spring.shardingsphere.datasource.ds-1.username=root spring.shardingsphere.datasource.ds-1.password= // 规则 spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=user_id spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=database-inline spring.shardingsphere.rules.sharding.binding-tables[0]=t_order,t_order_item spring.shardingsphere.rules.sharding.broadcast-tables=t_address spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=ds-$->{0..1}.t_order spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.column=order_id spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.key-generator-name=snowflake spring.shardingsphere.rules.sharding.tables.t_order_item.actual-data-nodes=ds-$->{0..1}.t_order_item spring.shardingsphere.rules.sharding.tables.t_order_item.key-generate-strategy.column=order_item_id spring.shardingsphere.rules.sharding.tables.t_order_item.key-generate-strategy.key-generator-name=snowflake spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.type=INLINE spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.props.algorithm-expression=ds-$->{user_id % 2} spring.shardingsphere.rules.sharding.key-generators.snowflake.type=SNOWFLAKE
- @MapperScan配置持久层的扫描路径
Sharding-JDBC怎样提供服务
- 通过调试发现,sharding-jdbc是通过mybatis提供的扩展点进行功能的增强
- 回顾一下mybatis的流程
2.1 通过@MapperScan导入MapperScannerRegistrar,注册MapperScannerConfigurer
2.2 MapperScannerConfigurer通过ClassPathMapperScanner扫描指定路径下的包,注册对应MapperFactoryBean的beanDefinition
2.3 MybatisAutoConfiguration配置SqlSessionFactory,注入到MapperFactoryBean中private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { // beanClassName:dao层接口名(org.apache.shardingsphere.example.core.mybatis.repository.MybatisAddressRepository) definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // beanClass为MapperFactoryBean definition.setBeanClass(this.mapperFactoryBeanClass); // 设置beanDefinition中按类型注入 --> 实例化MapperFactoryBean时会自动调用它的set方法 definition.setAutowireMode(2); }
2.4 MapperFactoryBean的getObject方法通过SqlSessionTemplate生成MapperProxy代理public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) { this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory); } }
- MapperProxy代理逻辑梳理
3.1 重点分析SimpleExecutor#doUpdate
3.2 Sharding-JDBC根据数据源配置生成ShardingSphereDataSource,通过数据源获取连接ShardingSphereConnectionpublic int doUpdate(MappedStatement ms, Object parameter) throws SQLException { // dataSource -> connection --> PreparedStatement stmt = this.prepareStatement(handler, ms.getStatementLog()); // 委托PreparedStatement执行update操作 var6 = handler.update(stmt); }
3.3 通过ShardingSphereConnection将sql封装成ShardingSpherePreparedStatement
3.4 通过ShardingSpherePreparedStatement委托执行update操作
小结
本篇文章主要介绍sql执行前注册流程以及代理执行流程,因为篇幅问题,对Sharding-JDBC具体怎样提供服务没有分析。下篇文章继续分析