利用ShardingSphere(sharding-proxy)实现分库分表,通过整合ZooKeeper,进行简单配置文件修改轻松实现跨库跨表相关操作,轻量级零侵入整合项目开发
分布式主键传统数据库软件开发中,主键自动生成技术是基本需求。而各个数据库对于该需求也提供了相应的支持,比如MySQL的自增键,Oracle的自增序列等。 数据分片后,不同数据节点生成全局唯一主键是非常棘手的问题。同一个逻辑表内的不同实际表之间的自增键由于无法互相感知而产生重复主键。 虽然可通过约束自增主键初始值和步长的方式避免碰撞,但需引入额外的运维规则,使解决...
利用ShardingSphere(sharding-proxy)实现分库分表,通过整合ZooKeeper,进行简单配置文件修改轻松实现跨库跨表相关操作,轻量级零侵入整合项目开发
准备工作
下载相关文件:https://download.csdn.net/download/u014374009/11837831
Linux和windows都可以使用!
1、解压文件
找到下面的文件夹,并进入。
在conf目录下进行配置。
修改下面两个配置文件中的一个配置文件,当然也可以全部都进行配置,第一个配置文件主要是进行主从数据库配置,第二个主要是进行数据库分库分表配置,也是本次主要演示的地方。
配置文件都很简单,基本上就是数据库连接信息。
在这里先创建两个数据库,在每个数据库下面分别建立四张表,相关的sql 建表语句在下载的文件中都有。
然后根据先前的配置文件,修改为自己的数据库连接配置信息。
接下来,配置server配置文件
其实主要就是把服务注册到 ZooKeeper 上,注意ZK的默认端口是2181,如果自己修改了,要对应的修改,下面会介绍ZK的安装配置。其次,就是配置用户名和密码,可以根据自己需要修改,这个在后面测试会用到。
下面是ZK的相关配置
在下载的文件夹中都有相关的文件。
进入conf目录。
把 zoo_sample.cfg 复制一份,改名为 zoo.cfg ,然后进行编辑。
主要配置一下数据和日志存放路径,这儿由于是windows系统,所以用了下面的路径,另外端口号,可以根据自己需要进行修改,一般不修改。
然后保存之后,到 ZK 的bin目录下,双击 zkServer.cmd 启动 ZK。
接着到 sharding-proxy-3.0.0 的 bin 目录下,双击 start.bat 启动sharding-proxy服务。
启动成功之后,会自动到 ZK 上注册服务,并会返回 registered 等信息,同时也会显示绑定的端口号,这个端口号就是后面数据库连接测试的端口号。
用Navicat进行测试,根据先前的信息,进行填写,端口号就是上面的,帐号密码就是 配置文件中 的 root,root。
连接成功,此时,环境已经搭建完成了。
测试工作
用Navicat连接成功后,会发现 数据库名字变为 配置文件中的名字,同时,两个数据库,四张表,变为一个数据库 两张表。
测试代码,可以根据自己需要修改。
package com.sharding.demo.controller;
import com.sharding.demo.bean.Order;
import com.sharding.demo.bean.OrderItem;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.sql.*;
/**
* @author: Frank
* @email 1320259466@qq.com
* @date: 2019/10/9
* @time: 8:52
* @fuction: about the role of class.
*/
public class TestSharingDB {
private static Logger logger = LogManager.getLogger();
public static void main(String[] args) {
DefaultKeyGenerator key = new DefaultKeyGenerator();
int userId = 45;
Number orderIdKey = key.generateKey();
Long orderId = orderIdKey.longValue();
logger.info("分布式主键orderId:" + orderId);
Number orderItemIdKey = key.generateKey();
Long orderItemId = orderItemIdKey.longValue();
logger.info("分布式主键orderItemId:" + orderItemId);
Order order = new Order();
order.setUserId(userId);
order.setStatus("1");
order.setOrderId(orderId);
//Long returnOrderId = orderService.insert(order);
Connection newConn = null;
Statement newSmt=null;
try
{
Class.forName("com.mysql.jdbc.Driver");
newConn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3307/sharding_db?serverTimezone=UTC&useSSL=false","root", "root");
if (newConn != null) {
newSmt = newConn.createStatement();
String sql="insert into t_order values ("+order.getOrderId()+","+order.getUserId()+",'"+order.getStatus()+"')";
// System.out.println(sql);
newSmt.executeUpdate(sql);//DDL语句返回值为0;
}
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
newSmt.close();
newConn.close();
} catch(SQLException e) {
throw new RuntimeException(e);
}
}
//logger.info("插入成功后的returnOrderId:" + returnOrderId);
OrderItem item = new OrderItem();
// item.setOrderItemId(orderItemId);
item.setOrderId(orderId);
item.setUserId(userId);
item.setStatus("1");
//Long returnOrderItemId = orderItemService.insert(item);
try
{
Class.forName("com.mysql.jdbc.Driver");
newConn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3307/sharding_db?serverTimezone=UTC&useSSL=false","root", "root");
if (newConn != null) {
newSmt = newConn.createStatement();
//String sql="insert into t_order values ('"+item.getOrderId()+"','"+item.getUserId()+"','"+item.getOrderItemId()+"','"+item.getStatus()+"')";
String sql="insert into t_order_item values ("+item.getOrderId()+","+item.getUserId()+","+item.getOrderItemId()+")";
// System.out.println(sql);
newSmt.executeUpdate(sql);//DDL语句返回值为0;
}
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
newSmt.close();
newConn.close();
} catch(SQLException e) {
throw new RuntimeException(e);
}
}
//logger.info("插入成功后的returnOrderItemId:" + returnOrderItemId);
try
{
Class.forName("com.mysql.jdbc.Driver");
newConn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3307/sharding_db?serverTimezone=UTC&useSSL=false","root", "root");
if (newConn != null) {
newSmt = newConn.createStatement();
//String sql="insert into t_order values ('"+item.getOrderId()+"','"+item.getUserId()+"','"+item.getOrderItemId()+"','"+item.getStatus()+"')";
String sql="select * from t_order join t_order_item on t_order_item.order_id=t_order.order_id";
// System.out.println(sql);
ResultSet rs = newSmt.executeQuery(sql);
while(rs.next()){
Long id = rs.getLong(1);
Long name = rs.getLong(2);
String gender = rs.getString(3);
System.out.println("id:"+id+" 姓名:"+name+" 性别:"+gender);
}
}
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
newSmt.close();
newConn.close();
} catch(SQLException e) {
throw new RuntimeException(e);
}
}
}
}
测试结果。
上面代码多次执行以后,在 sqlyog中发现,数据分配到不同的表中。
在Navicat中查看,会发现,表的数据是 每个表的数据的并集,也就是把所有的数据整合在一起了。可以在所有 ORM 框架中(可通过DataSource选择使用原生JDBC开发,或者在JPA、Hibernate或MyBatis中使用),对数据库进行增删查改了。
分布式主键
传统数据库软件开发中,主键自动生成技术是基本需求。而各个数据库对于该需求也提供了相应的支持,比如MySQL的自增键,Oracle的自增序列等。 数据分片后,不同数据节点生成全局唯一主键是非常棘手的问题。同一个逻辑表内的不同实际表之间的自增键由于无法互相感知而产生重复主键。 虽然可通过约束自增主键初始值和步长的方式避免碰撞,但需引入额外的运维规则,使解决方案缺乏完整性和可扩展性。
Sharding-proxy介绍
Sharding-Proxy是ShardingSphere的第二个产品。 它定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前先提供MySQL版本,它可以使用任何兼容MySQL协议的访问客户端(如:MySQL Command Client, MySQL Workbench等)操作数据,对DBA更加友好。
Atlas介绍
Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。目前该项目在360公司内部得到了广泛应用,很多MySQL业务已经接入了Atlas平台,每天承载的读写请求数达几十亿条。同时,有超过50家公司在生产环境中部署了Atlas,超过800人已加入,并且这些数字还在不断增加。
更多推荐
所有评论(0)