1 Sharding-Jdbc
介绍
Sharding-Jdbc
在 3.0
后改名为 Shardingsphere
。
它由 Sharding-JDBC
、Sharding-Proxy
和 Sharding-Sidecar
(计划中)这3款相互独立的产品组成。他们均提供标准化的 数据分片
、分布式事务
和 数据库治理
功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。
Sharding-Sphere
定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。
应用场景:
- 数据库读写分离
- 数据库分表分库
Sharding-Jdbc
官方网址:http://shardingsphere.io/index_zh.html
2 Sharding-Jdbc
与 MyCat
区别
MyCat
是一个基于第三方应用中间件数据库代理框架,客户端所有的 jdbc
请求都必须要先交给 MyCat
,再由 MyCat
转发到具体的真实服务器中。
Sharding-Jdbc
是一个 Jar
形式,在本地应用层重写 Jdbc
原生的方法,实现数据库分片形式。
MyCat
属于服务器端数据库中间件,而 Sharding-Jdbc
是一个 本地数据库中间件框架。
从设计理念上看确实有一定的相似性。主要流程都是 SQL 解析 -> SQL 路由 -> SQL 改写 -> SQL 执行 -> 结果归并
。但架构设计上是不同的。Mycat
是基于 Proxy
,它复写了 MySQL
协议,将 Mycat Server
伪装成一个 MySQL
数据库,而 Sharding-JDBC
是基于 JDBC
的扩展,是以 jar
包的形式提供轻量级服务的。
这也就是之前在微服务中学习的 SpringCloud Ribbon
与 Nginx
区别。
3 Sharding-Jdbc
实现读写分离
Sharding-Jdbc
实现读写分离原理,非常容易。只需要在项目中集成主和从的数据源,Sharding-Jdbc
自动根据 DML
和 DQL
语句类型连接主或者从数据源。
注意: Sharding-Jdbc
只是实现连接主或者从数据源,不会实现主从复制功能,需要自己配置数据库自带主从复制方式。
查看 MasterSlaveDataSource
即可查看该类 getDataSource
方法获取当前数据源名称
-
DQL
:数据查询语言DQL
基本结构是由SELECT
子句,FROM
子句,WHERE
子句组成的查询块:SELECT <字段名表> FROM <表或视图名> WHERE <查询条件>
-
DML
:数据操纵语言DML
主要有三种形式:- 插入:
INSERT
- 更新:
UPDATE
- 删除:
DELETE
- 创建:
CREATE
- 插入:
Sharding-Jdbc
只是单纯实现判断DML
或者是DQL
语句
4 SpringBoot
整合 Sharding-Jdbc
4.1 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.23</version>
</dependency>
<dependency>
<groupId>io.shardingjdbc</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>2.0.3</version>
</dependency>
4.2 application.yml
### 服务启动端口号
server:
port: 8400
mybatis-plus:
# mapper-locations: classpath*:/mapper/*.xml
global-config:
db-config:
column-underline: true
#shardingjdbc配置
sharding:
jdbc:
data-sources:
###配置第一个从数据库
ds_slave_0:
jdbc-url: jdbc:mysql://192.168.153.101:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
###主数据库配置
ds_master:
jdbc-url: jdbc:mysql://192.168.153.102:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
###配置读写分离
master-slave-rule:
###配置从库选择策略,提供轮询与随机,这里选择用轮询
load-balance-algorithm-type: round_robin
####指定从数据库
slave-data-source-names: ds_slave_0
name: ds_ms
####指定主数据库
master-data-source-name: ds_master
### 服务名称(服务注册到eureka名称)
spring:
application:
name: app-snow-mysql
### 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8100/eureka
### 问题:微信端口号是8200,会员端口号为8300?
### 目的是为了以后做集群方便分辨,例如:微信集群 82001、82002;会员集群:83001、83002。
### swagger相关配置
swagger:
base-package: com.snow.mysql.service # 扫描包的范围
title: SpringCloud2.x构建微服务项目-会员服务接口 # 标题
description: 该项目“基于SpringCloud2.x构建微服务项目”。 # 描述
version: 1.1 # 版本
terms-of-service-url: www.csdn.shop # 联系网址
contact:
name: yang # 姓名
email: [email protected] # 邮箱
4.3 启动项
package com.snow.mysql;
import com.spring4all.swagger.EnableSwagger2Doc;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author yang-windows
* @Title:
* @Package
* @Description:
* @date 2020/3/29 20:10
*/
@SpringBootApplication
@MapperScan(basePackages = "com.snow.mysql.mapper")
@EnableEurekaClient
@EnableSwagger2Doc
public class AppMysql {
public static void main(String[] args) {
SpringApplication.run(AppMysql.class);
}
}
4.4 实体类
package com.snow.api.entity.mysql;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class User {
private Long id;
private String name;
}
4.5 mapper
package com.snow.mysql.mapper;
import com.snow.api.entity.mysql.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author yang-windows
* @Title: snow-parent
* @Package com.snow.mysql.mapper
* @Description: UserMapper
* @date 2020/3/29 20:17
*/
public interface UserMapper {
@Select("SELECT * FROM user")
public List<User> findUser();
@Insert("insert into user(name) values (#{name}); ")
public int insertUser(@Param("name")String name);
}
4.6 service
package com.snow.mysql.service;
import com.snow.api.entity.mysql.User;
import com.snow.mysql.mapper.UserMapper;
import com.snow.service.api.mysql.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author yang-windows
* @Title:
* @Package
* @Description:
* @date 2020/3/29 20:13
*/
@RestController
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findUser() {
return userMapper.findUser();
}
@Override
public void insertUser(String name) {
int i = userMapper.insertUser(name);
System.out.println("i === " + i);
}
}
4.7 Config
配置信息
package com.snow.mysql.config;
import com.zaxxer.hikari.HikariDataSource;
import io.shardingjdbc.core.api.config.MasterSlaveRuleConfiguration;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashMap;
import java.util.Map;
/**
* @author yang-windows
* @Title: snow-parent
* @Package com.snow.mysql.config
* @Description: TODO
* @date 2020/3/30 23:36
*/
@Data
@ConfigurationProperties(prefix = "sharding.jdbc")
public class ShardingMasterSlaveConfig {
// 存放本地多个数据源
private Map<String, HikariDataSource> dataSources = new HashMap<>();
private MasterSlaveRuleConfiguration masterSlaveRule;
}
package com.snow.mysql.config;
import java.sql.SQLException;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.collect.Maps;
import io.shardingjdbc.core.api.MasterSlaveDataSourceFactory;
import lombok.extern.log4j.Log4j2;
/**
* @author yang-windows
* @Title: snow-parent
* @Package com.snow.mysql.config
* @Description: TODO
* @date 2020/3/30 23:37
*/
@Configuration
@EnableConfigurationProperties(ShardingMasterSlaveConfig.class)
@Log4j2
// 读取ds_master主数据源和读写分离配置
@ConditionalOnProperty({ "sharding.jdbc.data-sources.ds_master.jdbc-url",
"sharding.jdbc.master-slave-rule.master-data-source-name" })
public class ShardingDataSourceConfig {
@Autowired
private ShardingMasterSlaveConfig shardingMasterSlaveConfig;
@Bean
public DataSource masterSlaveDataSource() throws SQLException {
final Map<String, DataSource> dataSourceMap = Maps.newHashMap();
dataSourceMap.putAll(shardingMasterSlaveConfig.getDataSources());
final Map<String, Object> newHashMap = Maps.newHashMap();
// 创建 MasterSlave数据源
DataSource dataSource = MasterSlaveDataSourceFactory.createDataSource(dataSourceMap,
shardingMasterSlaveConfig.getMasterSlaveRule(), newHashMap);
log.info("masterSlaveDataSource config complete");
return dataSource;
}
}
4.8 测试
分别测试查询和插入接口,可以看到分别在对应的数据库查找和插入数据: