ShardingJDBC是一个数据库分库分表框架,它通过实现自定义的 javax.sql.DataSource
接口,将分库分表的逻辑封装在了里头,让客户端可以通过 JDBC
相对透明地访问分片数据库。但是,分片数据库有其固有之局限性,需要谨慎使用。
以SpringBoot+Maven+MySQL为例
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>bj</groupId>
<artifactId>hellomaven</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>hellomaven</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</project>
创建2库3表共6个user表: ds0.user0 ~ ds1.user2
import mysql.connector
conn = mysql.connector.connect(host='localhost', user='root', password='root', db='foo')
conn.autocommit = True
cursor = conn.cursor()
for i in range(0, 2):
cursor.execute(f"DROP SCHEMA IF EXISTS ds{i}")
cursor.execute(f"CREATE SCHEMA ds{i}")
for j in range(0, 3):
cursor.execute(f"CREATE TABLE ds{i}.user{j}(_id BIGINT, id INT, username VARCHAR(16))")
对应的SQL
DROP SCHEMA IF EXISTS ds0; CREATE SCHEMA ds0; CREATE TABLE ds0.user0(_id BIGINT, id INT, username VARCHAR(16)); CREATE TABLE ds0.user1(_id BIGINT, id INT, username VARCHAR(16)); CREATE TABLE ds0.user2(_id BIGINT, id INT, username VARCHAR(16)); DROP SCHEMA IF EXISTS ds1; CREATE SCHEMA ds1; CREATE TABLE ds1.user0(_id BIGINT, id INT, username VARCHAR(16)); CREATE TABLE ds1.user1(_id BIGINT, id INT, username VARCHAR(16)); CREATE TABLE ds1.user2(_id BIGINT, id INT, username VARCHAR(16));
ShardingJDBC的文档乍一看啥都有,仔细一看下不了手,文档跟项目还不同步,需要面向异常,随机应变。
以分库策略对2取模,分表策略对3取模为例:
sharding:
jdbc:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://localhost/ds0
username: root
password: root
ds1:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://localhost/ds1
username: root
password: root
config:
sharding:
tables:
user:
database-strategy:
inline:
sharding-column: id
algorithm-expression: ds$->{id % 2}
table-strategy:
inline:
sharding-column: id
algorithm-expression: user$->{id % 3}
key-generator-column-name: _id
logging:
level:
root: debug
package bj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@SpringBootApplication
@RestController
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Resource
private JdbcTemplate jdbcTemplate;
@GetMapping("/")
public Object index() {
jdbcTemplate.update("INSERT INTO user(id, username) VALUES (1, 'alpha')");
jdbcTemplate.update("INSERT INTO user(id, username) VALUES (2, 'beta')");
jdbcTemplate.update("INSERT INTO user(id, username) VALUES (3, 'gamma')");
jdbcTemplate.update("INSERT INTO user(id, username) VALUES (4, 'theta')");
List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT * FROM user WHERE id IN (0,1,2,3,4,5,6,7)");
System.out.println(maps);
return maps;
}
}
执行主程序,访问 localhost:8080/
,返回的JSON如下:
[
{
"_id": 273847537209704448,
"id": 4,
"username": "theta"
},
{
"_id": 273847537138401280,
"id": 2,
"username": "beta"
},
{
"_id": 273847537163567104,
"id": 3,
"username": "gamma"
},
{
"_id": 273847537096458240,
"id": 1,
"username": "alpha"
}
]
MySQL的SQL日志如下:
2018-11-26T08:12:20.690370Z 1697 Query INSERT INTO user1(id, username, _id) VALUES (1, 'alpha', 273847537096458240) 2018-11-26T08:12:20.698059Z 1696 Query INSERT INTO user2(id, username, _id) VALUES (2, 'beta', 273847537138401280) 2018-11-26T08:12:20.702720Z 1697 Query INSERT INTO user0(id, username, _id) VALUES (3, 'gamma', 273847537163567104) 2018-11-26T08:12:20.717724Z 1696 Query INSERT INTO user1(id, username, _id) VALUES (4, 'theta', 273847537209704448) 2018-11-26T08:12:20.729676Z 1697 Query SELECT * FROM user0 WHERE id IN (0,1,2,3,4,5,6,7) 2018-11-26T08:12:20.729705Z 1696 Query SELECT * FROM user0 WHERE id IN (0,1,2,3,4,5,6,7) 2018-11-26T08:12:20.732935Z 1697 Query SELECT * FROM user1 WHERE id IN (0,1,2,3,4,5,6,7) 2018-11-26T08:12:20.733504Z 1696 Query SELECT * FROM user1 WHERE id IN (0,1,2,3,4,5,6,7) 2018-11-26T08:12:20.736153Z 1697 Query SELECT * FROM user2 WHERE id IN (0,1,2,3,4,5,6,7) 2018-11-26T08:12:20.736612Z 1696 Query SELECT * FROM user2 WHERE id IN (0,1,2,3,4,5,6,7)
可见,ShardingJDBC确实执行了多库多表的插入与查询操作,而且生成了分布式自增ID