一、Sharding-JDBC介绍
1、这里引用官网上的介绍:
定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
2、自己的理解:
增强版的JDBC驱动,客户端使用的时候,就像正常使用JDBC驱动一样, 引入Sharding-JDBC依赖包,连接好数据库,配置好分库分表规则,读写分离配置,然后客户端的sql 操作 Sharding-JDBC会自动根据配置完成 分库分表和读写分离操作。
二、实现效果
1、下图展示了我们通过Sharding-JDBC实现的分库分表及读写分离效果图
分库分表:结合上一篇的主从,这里我们使用上次搭建的主从数据库,3307的app1是主数据库,3308的app1是对应的从数据库。同时,我们在3307新建app2库和user2表,这里的app2库需要和app1库一样,user2表和user1表结构一样,主从会自动帮我们建表同步到3308,然后我们在项目中使用Sharding-JDBC 配置响应的分库分表策略,使得插入数据的时候 根据配置字段的分片规则将数据打入对应的库和表。在我们这里主要是 根据分库的分片规则决定数据进入3307的app1库还是app2库,然后再根据分表的分片规则决定进入user1表还是user2表。
读写分离:读写分离 在我们这里主要指的是 我们项目DQL会根据Sharding-JDBC配置的master-slave-rule走的3308的数据源,而项目的DML会根据master-slave-rule走3307的数据源
三、Spring-Boot项目整合Sharding-JDBC实现分库分表、读写分离
1、这里创建一个maven项目,首先引入依赖,pom.xml文件如下。
4.0.0 org.springframework.boot spring-boot-starter-parent2.3.3.RELEASE com.cgg sharding-jdbc-test1.0-SNAPSHOT 1.8 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-testmysql mysql-connector-java8.0.15 com.alibaba druid1.1.21 com.baomidou mybatis-plus-boot-starter3.1.1 com.baomidou mybatis-plus-extension3.1.1 org.apache.shardingsphere sharding-jdbc-spring-boot-starter4.0.0-RC1 org.projectlombok lombokorg.springframework.boot spring-boot-maven-plugin
注意:这里使用的是4.0的sharding-jdbc,spring-boot的版本是2.x的,在整合过程中遇见了许多问题,后面会有错误的解决步骤。
2、application.yml文件如下
spring:
jpa:
properties:
hibernate:
hbm2ddl:
auto: create
dialect: org.hibernate.dialect.MySQL5Dialect
show_sql: true
shardingsphere:
props:
sql:
show: true
datasource:
names: master0,master0slave0,master1,master1slave0
master0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3307/app1?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: 654321
master1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3307/app2?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: 654321
master0slave0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3308/app1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT
username: root
password: 654321
master1slave0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3308/app2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT
username: root
password: 654321
sharding:
default-database-strategy:
inline:
sharding-column: id
algorithm-expression: app$->{(id % 2)+1}
tables:
user:
actual-data-nodes: app$->{1..2}.user$->{1..2}
table-strategy:
inline:
sharding-column: id
algorithm-expression: user$->{((""+id)[2..10].toInteger() % 2)+1}
key-generator:
column: id
type: SNOWFLAKE
master-slave-rules:
app1:
master-data-source-name: master0
slave-data-source-names: master0slave0
app2:
master-data-source-name: master1
slave-data-source-names: master1slave0
sharding:
jdbc:
config:
masterslave:
load-balance-algorithm-type: random
3、application.properties文件
spring.main.allow-bean-definition-overriding=true
mybatis-plus.mapper-locations= classpath:/mapper
@SpringBootTest(classes = ShardingJdbcApp.class)
@RunWith(SpringRunner.class)
public class AppTest {
@Resource
private IUserService userService;
@Test
public void testShardingJdbcInsert() {
userService.InsertUser();
}
@Test
public void testShardingJdbcQuery() {
//全部查询
userService.queryUserList();
//根据指定条件查询
userService.queryUserById(1452619866473324545L);
}
}
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
@Resource
private UserMapper userMapper;
@Resource
private DataSource dataSource;
@Override
public List queryUserList() {
List userList = userMapper.queryUserList();
userList.forEach(user -> System.out.println(user.toString()));
return userList;
}
@Override
public User queryUserById(Long id) {
User user = userMapper.selectOne(Wrappers.lambdaQuery().eq(User::getId, id));
System.out.println(user.toString());
return user;
}
@Override
public void InsertUser() {
for (int i = 20; i < 40; i++) {
User user = new User();
user.setName("XX-" + i);
int count = userMapper.insert(user);
System.out.println(count);
}
}
}
4.4.1、 首先看全部查询的结果
4.4.2、 再看下单条查询的结果
4.4.3、 再看下新增结果(实际插入到了主数据源的app1库user1表,并且后续每条插入都是走的主数据源,没有slave的操作)
四、问题及总结
到这里sharding-jdbc的初步基本使用已经没问题了,除了最简单的使用,我们还需要考虑分库分表后事务怎么处理,即分布式事务问题,还有读写分离后,数据不一致及同步延时问题,这些就需要我们从概念理论学习,然后在结合实际业务考虑方案。



