ShardingSphere-JDBC是一款可以将JDBC操作进行封装,然后实现数据分片、分布式事务、读写分离、高可用、数据加密和数据脱敏等功能的模块。它的原理是实现JDBC的接口,随后将收到的JDBC操作进行改写和处理,再将操作命中到真正的数据库之上。因为它实现了JDBC接口,因此现有的Java项目都可以100%兼容使用,只需要依赖ShardingSphere-JDBC并提供相关的配置即可。
我们看一个简单的JDBC数据分片的例子,首先我们需要添加相关的maven依赖
1 | <dependency> |
如上添加了shardingsphere-jdbc和mysql的依赖,shardingsphere-jdbc是项目的核心依赖,而mysql则是jdbc操作需要用到的依赖。添加了maven依赖之后我们可以先创建相关的数据库和表,创建数据库和表的sql如下
1 | ; |
我们会创建6个数据库,分别为ds_0到ds_5,并且会在每个数据库里面创建一个名叫t_order的表。
为了使用shardingsphere-jdbc,我们需要创建相应的jdbc连接和配置,因为shardingsphere-jdbc实现了jdbc的接口,所以我们可以像使用普通的jdbc一样使用shardingsphere-jdbc。创建shardingsphere-jdbc连接的代码如下
1 | Class.forName("org.apache.shardingsphere.driver.ShardingSphereDriver"); |
如上我们创建了一个shardingsphere-jdbc的连接,可以看到就是一个创建JDBC的过程。其中使用的SPI类是org.apache.shardingsphere.driver.ShardingSphereDriver,而具体的jdbcUrl则是一个文件地址shardingsphere-config.yaml,shardingsphere-jdbc的配置就保存在这个文件中。根据shardingsphere-jdbc的官方文档,其配置包含五大类:
shardingsphere-jdbc的配置支持Java代码和yaml文件,这里我们只介绍yaml文件,下面是一个简单的例子shardingsphere-config.yaml
1 | dataSources: |
如上配置了6个数据源分别是数据库ds_0到ds_5,props设置了打印sql语句,rules包含了表、分片算法和主键生成算法的配置。表设置中创建了一个逻辑表t_order,对应的真正数据库表是ds_0.t_order到ds_5.t_order,数据库的使用策略是通过id进行分片,分片算法是testInline,表的id字段的生成算法为snowflake。分片算法中定义了算法testInline,它使用INLINE内置方式来对id取模并和ds_进行拼接,构成数据库名。字段生成算法中定义了类型为SNOWFLAKE的字段生成算法。
有了如上配置之后,我们就可以使用shardingsphere-jdbc了。以一个数据插入操作为例,在引入了maven依赖、创建了相关的数据库和表、定义了相关的shardingsphere-jdbc配置之后,我们就可以使用上面创建的conn字段实现数据插入了。
1 | String sql = "INSERT INTO t_order (`user_id`, `order_id`) VALUES (?, ?)"; |
如上代码会创建一条数据并且随机根据snowflake算法生成一个id字段,并根据id字段的取模结果将数据保存到真正的数据库中去。更多的增删改查操作可在如下代码中看到:https://github.com/RitterHou/test-shardingsphere/tree/basic/src/main/java/com/nosuchfield/shardingsphere/data
根据官方issue,目前shardingsphere-jdbc已经不再使用spring-boot-starter,而是直接使用jdbc实现相关功能。这种方式可以完美兼容JDBC的相关接口,因此可以简化很多已有项目的使用。
在SpringBoot中使用ShardingSphere需要设置如下的pom配置,在这里我们使用MyBatis作为ORM框架。
1 | <?xml version="1.0" encoding="UTF-8"?> |
SpringBoot的application.yml配置如下,这里配置的数据源驱动为ShardingSphereDriver,而url就是我们配置ShardingSphere属性的地方。除此之外,我们还配置了mybatis的SQL语句所对应xml文件的路径信息。
1 | spring: |
接着我们配置ShardingSphere的配置信息config.yaml,这里的配置和上面简单使用的配置差不多,不再赘述了
1 | dataSources: |
接着我们定义一个订单模型Order,订单包含了一些属性信息
1 | public class Order { |
我们根据这个模型可以定义个MyBatis的Mapper,它包含了插入、查询的操作
1 | @Mapper |
其中getAllOrders方法通过注解实现了SQL的定义,而另外两个方法的SQL则在xml文件中进行实现
1 | <?xml version="1.0" encoding="UTF-8"?> |
构建了如上的ShardingSphere和MyBatis的配置之后,我们可以创建相关的数据库和表
1 | ; |
有了上面的数据库和表之后,我们就可以测试ShardingSphere的数据插入和查询了
1 | @Slf4j |
上面我们测试了ShardingSphere的数据分片功能,下面我们了解一下它的读写分离和数据脱敏。我们先在ds_0、ds_1和ds_2数据库中创建表t_user
1 | CREATE TABLE `t_user` ( |
之后我们在ShardingSphere的rules属性下添加如下配置
1 | - !READWRITE_SPLITTING |
配置包含了写库ds_0和读库ds_1、ds_2的配置,读库的负载均衡策略为随机(这里需要先设置ds_1和ds_2自动同步ds_0的数据,详细过程可查看文章MySQL实现双服务器主从同步)。数据脱敏策略为对t_user的id字段进行md5脱敏,对phone字段保留前3位和后4位,剩下的部分用*替换。创建好了表和配置之后,我们设置User的model
1 | public class User { |
以及mapper
1 | @Mapper |
之后我们测试上面的操作
1 | @Slf4j |
我们先插入数据,随后到从库中查询数据,得到结果如下
ShardingSphere-SQL:73 Logic SQL: SELECT * FROM t_user
ShardingSphere-SQL:73 Actual SQL: ds_1 ::: SELECT * FROM t_user
com.nosuchfield.shardingsphere.UserMapperTest:30 [User(id=0a113ef6b61820daa5611c870ed8d5ee, name=小明, phone=138****8888, address=江苏省南京市)]
可以看到数据插入到了主库中,随后从从库ds_1中查询出了相关的数据,并且对id和phone字段的数据进行了脱敏操作,id字段被转化为了MD5的结果,而phone的中间4位被星号替代了。
数据加密可以保证我们存到数据库中的数据都是经过加密的,和数据脱敏刚好反过来。首先我们创建表t_member
1 | CREATE TABLE `t_member` ( |
随后我们配置ShardingSphere的数据加密配置
1 | - !ENCRYPT |
我们将表t_member的name字段使用name_encryptor的加密方式进行加密,加密之后的字段名仍然叫做name,name_encryptor的配置在encryptors中可以看到,使用了AES加密算法并设置key为123abc。类似的,password的加密方式为MD5,在计算MD5的时候加盐nosuchfield。
随后我们创建model
1 | public class Member { |
和mapper
1 | @Mapper |
并测试写入和读取
1 | @Slf4j |
在插入了数据{"name": "张三", "password": "123456"}之后,可以到数据库中查看插入的数据如下
PS C:\Program Files\MySQL\MySQL Server 8.0\bin> ./mysql -u root -p
mysql> select * from t_member;
+--------------------------+----------------------------------+
| name | password |
+--------------------------+----------------------------------+
| Fod6ouOanqNvHlTdBsx1Lw== | 47514eed77109a04ce4c9f9931d0c5ec |
+--------------------------+----------------------------------+
1 row in set (0.00 sec)
可以看到name和password在存储到数据库的时候都加密了。随后我们执行测试代码中的查询逻辑,可以看到结果如下,name又通过AES算法解密成功,而password因为使用的是MD5算法就无法解密了
com.nosuchfield.shardingsphere.MemberMapperTest:27 [Member(name=张三, password=47514eed77109a04ce4c9f9931d0c5ec)]
本节使用到的代码:https://github.com/RitterHou/test-shardingsphere
ShardingSphere-JDBC是一款可以将JDBC操作进行封装,然后实现数据分片、分布式事务、读写分离、高可用、数据加密和数据脱敏等功能的模块。它的原理是实现JDBC的接口,随后将收到的JDBC操作进行改写和处理,再将操作命中到真正的数据库之上。因为它实现了JDBC接口,因此现有的Java项目都可以100%兼容使用,只需要依赖ShardingSphere-JDBC并提供相关的配置即可。
我们看一个简单的JDBC数据分片的例子,首先我们需要添加相关的maven依赖
1 | <dependency> |
如上添加了shardingsphere-jdbc和mysql的依赖,shardingsphere-jdbc是项目的核心依赖,而mysql则是jdbc操作需要用到的依赖。添加了maven依赖之后我们可以先创建相关的数据库和表,创建数据库和表的sql如下
1 | ; |
我们会创建6个数据库,分别为ds_0到ds_5,并且会在每个数据库里面创建一个名叫t_order的表。
为了使用shardingsphere-jdbc,我们需要创建相应的jdbc连接和配置,因为shardingsphere-jdbc实现了jdbc的接口,所以我们可以像使用普通的jdbc一样使用shardingsphere-jdbc。创建shardingsphere-jdbc连接的代码如下
1 | Class.forName("org.apache.shardingsphere.driver.ShardingSphereDriver"); |
如上我们创建了一个shardingsphere-jdbc的连接,可以看到就是一个创建JDBC的过程。其中使用的SPI类是org.apache.shardingsphere.driver.ShardingSphereDriver,而具体的jdbcUrl则是一个文件地址shardingsphere-config.yaml,shardingsphere-jdbc的配置就保存在这个文件中。根据shardingsphere-jdbc的官方文档,其配置包含五大类:
shardingsphere-jdbc的配置支持Java代码和yaml文件,这里我们只介绍yaml文件,下面是一个简单的例子shardingsphere-config.yaml
1 | dataSources: |
如上配置了6个数据源分别是数据库ds_0到ds_5,props设置了打印sql语句,rules包含了表、分片算法和主键生成算法的配置。表设置中创建了一个逻辑表t_order,对应的真正数据库表是ds_0.t_order到ds_5.t_order,数据库的使用策略是通过id进行分片,分片算法是testInline,表的id字段的生成算法为snowflake。分片算法中定义了算法testInline,它使用INLINE内置方式来对id取模并和ds_进行拼接,构成数据库名。字段生成算法中定义了类型为SNOWFLAKE的字段生成算法。
有了如上配置之后,我们就可以使用shardingsphere-jdbc了。以一个数据插入操作为例,在引入了maven依赖、创建了相关的数据库和表、定义了相关的shardingsphere-jdbc配置之后,我们就可以使用上面创建的conn字段实现数据插入了。
1 | String sql = "INSERT INTO t_order (`user_id`, `order_id`) VALUES (?, ?)"; |
如上代码会创建一条数据并且随机根据snowflake算法生成一个id字段,并根据id字段的取模结果将数据保存到真正的数据库中去。更多的增删改查操作可在如下代码中看到:https://github.com/RitterHou/test-shardingsphere/tree/basic/src/main/java/com/nosuchfield/shardingsphere/data
根据官方issue,目前shardingsphere-jdbc已经不再使用spring-boot-starter,而是直接使用jdbc实现相关功能。这种方式可以完美兼容JDBC的相关接口,因此可以简化很多已有项目的使用。
在SpringBoot中使用ShardingSphere需要设置如下的pom配置,在这里我们使用MyBatis作为ORM框架。
1 | <?xml version="1.0" encoding="UTF-8"?> |
SpringBoot的application.yml配置如下,这里配置的数据源驱动为ShardingSphereDriver,而url就是我们配置ShardingSphere属性的地方。除此之外,我们还配置了mybatis的SQL语句所对应xml文件的路径信息。
1 | spring: |
接着我们配置ShardingSphere的配置信息config.yaml,这里的配置和上面简单使用的配置差不多,不再赘述了
1 | dataSources: |
接着我们定义一个订单模型Order,订单包含了一些属性信息
1 | public class Order { |
我们根据这个模型可以定义个MyBatis的Mapper,它包含了插入、查询的操作
1 | @Mapper |
其中getAllOrders方法通过注解实现了SQL的定义,而另外两个方法的SQL则在xml文件中进行实现
1 | <?xml version="1.0" encoding="UTF-8"?> |
构建了如上的ShardingSphere和MyBatis的配置之后,我们可以创建相关的数据库和表
1 | ; |
有了上面的数据库和表之后,我们就可以测试ShardingSphere的数据插入和查询了
1 | @Slf4j |
上面我们测试了ShardingSphere的数据分片功能,下面我们了解一下它的读写分离和数据脱敏。我们先在ds_0、ds_1和ds_2数据库中创建表t_user
1 | CREATE TABLE `t_user` ( |
之后我们在ShardingSphere的rules属性下添加如下配置
1 | - !READWRITE_SPLITTING |
配置包含了写库ds_0和读库ds_1、ds_2的配置,读库的负载均衡策略为随机(这里需要先设置ds_1和ds_2自动同步ds_0的数据,详细过程可查看文章MySQL实现双服务器主从同步)。数据脱敏策略为对t_user的id字段进行md5脱敏,对phone字段保留前3位和后4位,剩下的部分用*替换。创建好了表和配置之后,我们设置User的model
1 | public class User { |
以及mapper
1 | @Mapper |
之后我们测试上面的操作
1 | @Slf4j |
我们先插入数据,随后到从库中查询数据,得到结果如下
ShardingSphere-SQL:73 Logic SQL: SELECT * FROM t_user
ShardingSphere-SQL:73 Actual SQL: ds_1 ::: SELECT * FROM t_user
com.nosuchfield.shardingsphere.UserMapperTest:30 [User(id=0a113ef6b61820daa5611c870ed8d5ee, name=小明, phone=138****8888, address=江苏省南京市)]
可以看到数据插入到了主库中,随后从从库ds_1中查询出了相关的数据,并且对id和phone字段的数据进行了脱敏操作,id字段被转化为了MD5的结果,而phone的中间4位被星号替代了。
数据加密可以保证我们存到数据库中的数据都是经过加密的,和数据脱敏刚好反过来。首先我们创建表t_member
1 | CREATE TABLE `t_member` ( |
随后我们配置ShardingSphere的数据加密配置
1 | - !ENCRYPT |
我们将表t_member的name字段使用name_encryptor的加密方式进行加密,加密之后的字段名仍然叫做name,name_encryptor的配置在encryptors中可以看到,使用了AES加密算法并设置key为123abc。类似的,password的加密方式为MD5,在计算MD5的时候加盐nosuchfield。
随后我们创建model
1 | public class Member { |
和mapper
1 | @Mapper |
并测试写入和读取
1 | @Slf4j |
在插入了数据{"name": "张三", "password": "123456"}之后,可以到数据库中查看插入的数据如下
PS C:\Program Files\MySQL\MySQL Server 8.0\bin> ./mysql -u root -p
mysql> select * from t_member;
+--------------------------+----------------------------------+
| name | password |
+--------------------------+----------------------------------+
| Fod6ouOanqNvHlTdBsx1Lw== | 47514eed77109a04ce4c9f9931d0c5ec |
+--------------------------+----------------------------------+
1 row in set (0.00 sec)
可以看到name和password在存储到数据库的时候都加密了。随后我们执行测试代码中的查询逻辑,可以看到结果如下,name又通过AES算法解密成功,而password因为使用的是MD5算法就无法解密了
com.nosuchfield.shardingsphere.MemberMapperTest:27 [Member(name=张三, password=47514eed77109a04ce4c9f9931d0c5ec)]
本节使用到的代码:https://github.com/RitterHou/test-shardingsphere