springboot + sharding-jdbc 学习
官网地址:http://shardingsphere.io/document/current/cn/overview/
sharding-jdbc事务:https://blog.csdn.net/yanyan19880509/article/details/78335935
1简介
通过docker搭建四台mysql,两主,每台一从;springboot搭建简单的web项目,并配置sharding-jdbc实现分库分表+独写分离;
sharding-jdbc是在datasource层做的代理,对应用透明,只需在datasource配置好读写分离/分库分表策略即可,原理可参见官网;
2 docker搭建mysql
硬件环境:虚拟机 centos7 4G内存 20G硬盘 mysql5.7.13
1 安装docker : yum install docker 并启动
2 获取mysql镜像: docker pull mysql:5.7.13
3 在虚拟机上配置四台mysql配置文件my.cnf,目录结构如下,主要是配置log-bin和server-id,主从之间server-id不能相同
tip:可以先启动一台mysql容器,然后拷贝容器的配置到本地 docker cp mysql:/etc/mysql/my.cnf /etc/mysql/master-order0/,再在这配置中修改log-bin和server-id
4 启动mysql容器 :
docker run --name master-order0 -d -p 13306:3306 -v /etc/mysql/master-order0/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.13 //主 master0
docker run --name master-order1 -d -p 23306:3306 -v /etc/mysql/master-order1/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.13 //主master1
docker run --name slave-order0 -d -p 13307:3306 -v /etc/mysql/slave-order0/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.13 //从slave0 作为master0的从
docker run --name slave-order1 -d -p 23307:3306 -v /etc/mysql/master-order0/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.13 //从slave1 作为master1的从
说明 --name 指定容器名称,-d后台运行 -v 使用本地配置代替容器自身的配置文件 -e 设置mysql root密码
配置主从:配置前需要关闭虚拟机防火墙 : service firewalld stop
进入 slave-order0: docker exec -it slave-order0 /bin/bash
进入mysql:mysql -uroot -p123456
配置主从: change master to MASTER_HOST='主机ip',MASTER_PORT=13306,MASTER_USER='ROOT',MASTER_PASSWORD='123456',
MASTER_LOG_FILE='主中的log-bin名称',MASTER_LOG_POS=主机log-bin的pos ;
其中MASTER_LOG_FILE和MASTER_LOG_POS需要到主上查看 ,进入主master-order0数据库,show master status \G 可以查看到这两个参数
另外的master-order1和slave-order1配置方式相同;
在两主上建立相同的库和表,库 tyyd; 每个库上新建两张表 order0,order1 表结构相同,表id不要设置为自增,由sharding-jdbc生成;
可以到从数据库上查看到对应的库和表也已经生成;
3springboot+sharding-jdbc搭建web项目
idea中新建web项目,引入sharding-jdbc maven依赖
<!-- https://mvnrepository.com/artifact/io.shardingsphere/sharding-jdbc -->
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc</artifactId>
<version>3.0.0.M2</version>
</dependency>
1 配置sharding-jdbc 分库分表+独写分离 datasource(也可以采用只独写分离或只分库分表),可以有多种配置方式,我采用的是代码的配置方式:
/**
* @author cgl
* @date 2018/8/15 11:12
* <p>
* 读写分离+分库分表
*/
@Configuration
public class ShardingJDBCSplitAndMsDataSourceConfig {
@Bean
DataSource getDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
// shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
// shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item"); //分库策略:根据参数userId取摸计算,此处的ds和下面一行中的order都是逻辑库/表名
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));
//分表策略:根据参数id取模计算
shardingRuleConfig.setDefaultTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "order${id % 2}"));
shardingRuleConfig.setMasterSlaveRuleConfigs(getMasterSlaveRuleConfigurations());
//实际项目需自定义keyGenerator或使用默认的
shardingRuleConfig.setDefaultKeyGenerator(System::currentTimeMillis );
return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap<>(), new Properties());
} TableRuleConfiguration getOrderTableRuleConfiguration() {
TableRuleConfiguration result = new TableRuleConfiguration();
result.setLogicTable("order");
result.setActualDataNodes("ds${0..1}.order${0..1}");
result.setKeyGeneratorColumnName("id");
return result;
} List<MasterSlaveRuleConfiguration> getMasterSlaveRuleConfigurations() {
MasterSlaveRuleConfiguration masterSlaveRuleConfig1 = new MasterSlaveRuleConfiguration("ds0", "ds_master_0", Arrays.asList("ds_master_0_slave_0"));
MasterSlaveRuleConfiguration masterSlaveRuleConfig2 = new MasterSlaveRuleConfiguration("ds1", "ds_master_1", Arrays.asList("ds_master_1_slave_0"));
return Lists.newArrayList(masterSlaveRuleConfig1, masterSlaveRuleConfig2);
} Map<String, DataSource> createDataSourceMap() {
final Map<String, DataSource> result = new HashMap<>();
result.put("ds_master_0", createDatasource("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.137.128:13306/tyyd?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"));
result.put("ds_master_1", createDatasource("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.137.128:23306/tyyd?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"));
result.put("ds_master_0_slave_0", createDatasource("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.137.128:13307/tyyd?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"));
result.put("ds_master_1_slave_0", createDatasource("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.137.128:23307/tyyd?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"));
return result;
} private HikariDataSource createDatasource(String driverClassName, String jdbcUrl, String userName, String password) {
HikariConfig hikariConfig0 = new HikariConfig();
hikariConfig0.setDriverClassName(driverClassName);
hikariConfig0.setJdbcUrl(jdbcUrl);
hikariConfig0.setUsername(userName);
hikariConfig0.setPassword(password);
return new HikariDataSource(hikariConfig0);
}
}
2 编写order Controller crud操作
package com.sj.web.controller;
import com.sj.client.request.order.OrderAddRequest;
import com.sj.client.request.order.OrderUpdateRequest;
import com.sj.client.response.order.OrderDetail;
import com.sj.client.service.order.OrderService;
import com.sj.web.dto.BaseResponse;
import com.sj.web.dto.order.OrderDTO;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; /**
* @author cgl
* @date 2018/8/16 15:00
*/
@RestController
@RequestMapping("/order")
public class OrderController { @Autowired
private OrderService orderService;
@RequestMapping("/get/{id}/{userId}")
public OrderDTO getOrderInfo(@PathVariable("id") long id,@PathVariable("userId") long userId){
Optional<OrderDetail> orderDetailOptional = orderService.getOrderInfoByOrderId(id,userId);
if(orderDetailOptional.isPresent()){
OrderDetail detail = orderDetailOptional.get();
return convert(detail);
}
return new OrderDTO();
} private OrderDTO convert(OrderDetail detail) {
OrderDTO dto=new OrderDTO();
dto.setId(detail.getId());
dto.setPrice(detail.getPrice());
dto.setProdId(detail.getProdId());
dto.setUserId(detail.getUserId());
return dto;
} @RequestMapping("/delete/{id}/{userId}")
public BaseResponse delete(@PathVariable("id") long id,@PathVariable("userId") long userId){
orderService.deleteOrder(id,userId);
return new BaseResponse();
} @RequestMapping("/update")
public BaseResponse update(@RequestBody OrderDTO order){
OrderUpdateRequest updateOrder=new OrderUpdateRequest();
updateOrder.setId(order.getId());
updateOrder.setPrice(order.getPrice());
updateOrder.setProdId(order.getProdId());
updateOrder.setUserId(order.getUserId());
orderService.updateOrder(updateOrder);
return new BaseResponse();
} @RequestMapping("/add")
public BaseResponse add(@RequestBody OrderDTO order){
OrderAddRequest request=new OrderAddRequest();
request.setPrice(order.getPrice());
request.setProdId(order.getProdId());
request.setUserId(RandomUtils.nextInt(10,20));
orderService.insertOrder(request);
BaseResponse baseResponse = new BaseResponse();
return baseResponse;
} @RequestMapping("/getlist/{userId}")
public BaseResponse orderList(@PathVariable long userId){
List<OrderDetail>orders= orderService.getOrderListByUserId(userId);
List<OrderDTO> orderDTOS = orders.stream().map(this::convert).collect(Collectors.toList());
BaseResponse response=new BaseResponse();
response.setSuccess(true);
response.setCode(200);
response.setData(orderDTOS);
return response;
}
}
其他service层代码就是简单调用,mapper代码
@Mapper
public interface OrderMapper { @Select("select id,prod_id prodId,user_id userId,price from order where id =#{id} and user_id=#{userId}")
Order selectByPrimaryKey(@Param("id") long id,@Param("userId") long userId);
//此处不应出现id,否则sharding-jdbc不会自动生成id
@Insert("insert into order (prod_id,user_id,price) value(#{prodId},#{userId},#{price} )")
void insertOrder(Order order); @Delete("delete from order where id=#{id} and user_id=#{userId}")
void deleteById(@Param("id") long id,@Param("userId")long userId); @Update("update order set prod_id=#{prodId},user_id=#{userId},price=#{price} where id=#{id}")
void updateOrder(Order order); @Select("select id,prod_id prodId,user_id userId,price from order where user_id=#{userId}")
List<Order> selectListByUserId(long userId);
}
4测试
新增/获取/获取列表 等都正常。测试结果略
以上是这两天学习sharding-jdbc的简单入门demo,前路漫漫~~
springboot + sharding-jdbc 学习的更多相关文章
- Sharding JDBC整合SpringBoot 2.x 和 MyBatis Plus 进行分库分表
Sharding JDBC整合SpringBoot 2.x 和 MyBatis Plus 进行分库分表 交易所流水表的单表数据量已经过亿,选用Sharding-JDBC进行分库分表.MyBatis-P ...
- SpringBoot系列之学习教程汇总
对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 一.配置篇 SpringBoot系列之@PropertySource读取yaml文件 >> source down ...
- Sharding jdbc 强制路由策略(HintShardingStrategy)使用记录
背景 随着项目运行时间逐渐增加,数据库中的数据也越来越多,虽然加索引,优化查询,但是数据量太大,还是会影响查询效率,也给数据库增加了负载. 再加上冷数据基本不使用的场景,决定采用分表来处理数据,从而来 ...
- JDBC学习笔记(2)——Statement和ResultSet
Statement执行更新操作 Statement:Statement 是 Java 执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句.Statement ...
- JDBC学习笔记(1)——JDBC概述
JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据库连接. JDBC库中所包含的API任务通常与数据库使用: 连接到数 ...
- 【转】JDBC学习笔记(2)——Statement和ResultSet
转自:http://www.cnblogs.com/ysw-go/ Statement执行更新操作 Statement:Statement 是 Java 执行数据库操作的一个重要方法,用于在已经建立数 ...
- 【转】JDBC学习笔记(1)——JDBC概述
转自:http://www.cnblogs.com/ysw-go/ JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据 ...
- jdbc学习总结
jdbc学习总结: 一.简介: jdbc,直译为java连接数据库.实际为java为很好的操作数据库而提供的一套接口,接口的实现(即驱动)由各个数据库厂商提供. 二.知识要点: 连接5要素,3 ...
- SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能
在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...
- SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证
整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...
随机推荐
- 《零压力学Python》 之 第一章知识点归纳
第一章(初识Python)知识点归纳 Python是从ABC语言衍生而来的 ABC语言是Guido参与设计的一种教学语言,为非专业编程人员所开发的. Python是荷兰程序员 Guido Van Ro ...
- jQuery WEI----DIV+CSS样式li自动适应高度,自动换行,横向排列
设置相关样式即可,按照需求自己修改样式,Demo代码如下: <li style="display:inline;;line-height:24px;height:auto;word-b ...
- const关键字作用
const int a; int const a; const int *a; int * const a; int const * a const; /******/ 前两个的作用是一样,a是一个常 ...
- IDFTP连不上FTP服务器的解决方法
使用IDFTP连不上FTP服务端. 原来是IDFTP有2种模式:主动模式和被动模式. IDFTP默认是使用主动模式,如果FTP服务端设置使用被动模式,使用IDFTP连不上FTP服务端的. 解决方法: ...
- [转]趣题:一个n位数平均有多少个单调区间?---- From Matrix67
考虑这么一个 14 位数 02565413989732 ,如图所示,它的数字先逐渐变大,然后开始变小,再变大,再变小,再变大,再变小.我们就说,它一共包含了 6 个单调区间.我们的问题就是:一个 n ...
- 欧几里得 & 拓展欧几里得算法 解说 (Euclid & Extend- Euclid Algorithm)
欧几里得& 拓展欧几里得(Euclid & Extend-Euclid) 欧几里得算法(Euclid) 背景: 欧几里德算法又称辗转相除法.用于计算两个正整数a.b的最大公约数. -- ...
- T4语法
阅读目录 阅读目录 1.什么是T4? 2.vs插件的安装 3.T4初体验 4.T4语法 其实对于“T4模板”的学习,讲得最详细的还是MSDN,下面给出对应的链接,可以点开深入的了解. 回到顶部 1 ...
- WPF学习笔记——在“System.Windows.StaticResourceExtension”上提供值时引发了异常
在"System.Windows.StaticResourceExtension"上提供值时引发了异常 因应需要,写了一个转换器,然后窗体上引用,结果就出来这个错.编译的时候没事, ...
- 一条SQL语句求每月连续低温时间
近期为某个项目写存储过程做统计.其中有个是这样的: 求每个月至少连续3个小时低于某个温度值的时间(小时). 假设有个全年温度表: CREATE TABLE #t(m INT, h INT ,t DEC ...
- 莫队&&分块
今天兔哥讲了一波莫队,比较有趣,先加一个链接,这是她的教程 rabbithu.cnblogs.com 这里就不详细说了,其实就是两个指针来优化的暴力.一开始排序函数有问题,没用上莫队的核心思想:把查询 ...