shardingjdbc实现分表分库
2019/09/04 15:05 分类: 技术交流 浏览:0
一、Sharding-JDBC简介**
定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
l 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
l 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
l 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。
二、Sharding-JDBC实现数据库分表分库
分片:
数据分片指按照某个维度将存放在单一数据库中的数据分散地存放至多个数据库或表中以达到提升性能瓶颈以及可用性的效果。 数据分片的有效手段是对关系型数据库进行分库和分表。分库和分表均可以有效的避免由数据量超过可承受阈值而产生的查询瓶颈。 除此之外,分库还能够用于有效的分散对数据库单点的访问量;分表虽然无法缓解数据库压力,但却能够提供尽量将分布式事务转化为本地事务的可能,一旦涉及到跨库的更新操作,分布式事务往往会使问题变得复杂。 使用多主多从的分片方式,可以有效的避免数据单点,从而提升数据架构的可用性。
通过分库和分表进行数据的拆分来使得各个表的数据量保持在阈值以下,以及对流量进行疏导应对高访问量,是应对高并发和海量数据系统的有效手段。 数据分片的拆分方式又分为垂直分片和水平分片。
垂直分片:
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。 下图展示了根据业务需要,将用户表和订单表垂直分片到不同的数据库的方案。
水平分片:
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。 例如:根据主键分片,偶数主键的记录放入0库(或表),奇数主键的记录放入1库(或表),如下图所示。
1、水平分库
1)、概念: 以字段为依据,按照一定策略,将一个库中的数据拆分到多个库中。
2)、结果 每个库的结构都一样;数据都不一样; 所有库的并集是全量数据;
2、水平分表
1)、概念 以字段为依据,按照一定策略,将一个表中的数据拆分到多个表中。
2)、结果 每个表的结构都一样;数据都不一样; 所有表的并集是全量数据;
三、项目结构
application.properties
mybatis.type-aliases-package=cn.terry.sharddemo.mapper mybatis.mapper-locations=classpath:mybatis/*.xml spring.profiles.active=sharding #datasource spring.devtools.remote.restart.enabled=false sharding.jdbc.datasource.names=ds0,ds1 sharding.jdbc.datasource.ds0.type=org.apache.commons.dbcp.BasicDataSource sharding.jdbc.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver sharding.jdbc.datasource.ds0.url=jdbc:mysql://127.0.0.1:3307/shardtest1?serverTimezone=UTC sharding.jdbc.datasource.ds0.username=root sharding.jdbc.datasource.ds0.password=Admin123! sharding.jdbc.datasource.ds1.type=org.apache.commons.dbcp.BasicDataSource sharding.jdbc.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver sharding.jdbc.datasource.ds1.url=jdbc:mysql://127.0.0.1:3307/shardtest2?serverTimezone=UTC sharding.jdbc.datasource.ds1.username=root sharding.jdbc.datasource.ds1.password=Admin123! #分库策略 根据user_id sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=user_id #对user_id取模 确定数据所在数据库 sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2} #分表策略 sharding.jdbc.config.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order_$->{0..1} sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id #对订单号进行hash运算 确定数据所在表名 sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2} sharding.jdbc.config.sharding.tables.t_order.key-generator-column-name=order_id
pom 文件
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.terry</groupId> <artifactId>sharddemo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sharddemo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!-- for spring boot --> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>3.0.0.M1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Controller
package cn.terry.sharddemo.controller; import cn.terry.sharddemo.domain.Order; import cn.terry.sharddemo.service.impl.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @version V1.0 * @Title: OrderController * @Package cn.terry.sharddemo.controller * @Description: * @author: Terry * @date: 2019-04-19 17:52 */ @RestController @RequestMapping("/order") public class OrderController { @Autowired OrderService service; @PostMapping("/test") public String test(@RequestBody(required = false) Order order) { service.demo(order); return "测试成功"; } }
Domain
package cn.terry.sharddemo.domain; import lombok.Data; /** * @version V1.0 * @Title: Order * @Package cn.terry.sharddemo.domain * @Description: * @author: Terry * @date: 2019-04-19 17:30 */ @Data public class Order { private long orderId; private int userId; private String status; }
Mapper
package cn.terry.sharddemo.mapper; import cn.terry.sharddemo.domain.Order; import org.apache.ibatis.annotations.Mapper; /** * @version V1.0 * @Title: OrderMapper * @Package cn.terry.sharddemo.mapper * @Description: * @author: Terry * @date: 2019-04-19 17:32 */ @Mapper public interface OrderMapper { Long insert(Order order); }
Service
package cn.terry.sharddemo.service.impl; import cn.terry.sharddemo.domain.Order; import cn.terry.sharddemo.mapper.OrderMapper; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @version V1.0 * @Title: OrderService * @Package cn.terry.sharddemo.service.impl * @Description: * @author: Terry * @date: 2019-04-19 17:33 */ @Service public class OrderService { @Resource private OrderMapper orderRepository; public void demo(Order order) { orderRepository.insert(order); System.out.println("Insert Success"); } }
OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.terry.sharddemo.mapper.OrderMapper"> <insert id="insert" useGeneratedKeys="true" keyProperty="orderId"> INSERT INTO t_order ( order_id,user_id, status ) VALUES ( #{orderId}, #{userId,jdbcType=INTEGER}, #{status,jdbcType=VARCHAR} ) </insert> </mapper>
数据库:(shardtest1和shardtest2表结构完全相同)
DROP TABLE IF EXISTS t_order_0
; CREATE TABLE t_order_0
( order_id
bigint(20) NOT NULL AUTO_INCREMENT, user_id
int(11) NULL DEFAULT NULL, status
varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (order_id
) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- Table structure for t_order_1
DROP TABLE IF EXISTS t_order_1
; CREATE TABLE t_order_1
( order_id
bigint(20) NOT NULL AUTO_INCREMENT, user_id
int(11) NULL DEFAULT NULL, status
varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (order_id
) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
赞 0