- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringBoot集成Sharding Jdbc使用复合分片的实践由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
最近主要的工作重心是数据库的容量规划.
随着业务的逐渐增大,原有保存在单表的数据量也日益增强。数据库数据会随着业务的发展而不断增多,因此数据操作,如增删改查的开销也会越来越大。再加上物理服务器的资源有限(CPU、磁盘、内存、IO 等)。最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。换句话说需要合理的数据库架构来存放不断增长的数据,这个就是分库分表的设计初衷。目的就是为了缓解数据库的压力,大限度提高数据操作的效率.
数据库分库分表中间件是采用的 apache sharding.
。
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景.
ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 它与NoSQL和NewSQL是并存而非互斥的关系。NoSQL和NewSQL作为新技术探索的前沿,放眼未来,拥抱变化,是非常值得推荐的。反之,也可以用另一种思路看待问题,放眼未来,关注不变的东西,进而抓住事物本质。 关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆.
ShardingSphere已经在2020年4月16日从Apache孵化器毕业,成为Apache顶级项目.
。
因为我们公司属于第三方支付平台,这个改造的点可以分为两类:提供给商户调用的对接系统(比如收银台),系统内部调用的系统(支付引擎).
数据源使用分库分表,在 Sharding JDBC 当中如果进行 修改、删除、查询操作中没有包含分片键就会进行全表扫描。所以在进行业务改造的时候对原有的数据库操作都进行了业务优化,基本改造后的所有的操作都使用了基于分片键进行操作(定时任务除外).
首先讨论一下,提供给商户调用的系统。在进行下单操作的时候,商户必须传递商户号和外部订单号。对于外部订单号第三方支付系统无法控制,只需要商户每次传递过来的时候与历史的外部订单号不重复就可以了。所以这里就涉及到一张映射表,这个表的主要功能如下:
这个时候对交易订单就依赖于外部映射表,把请求映射成内部订单号进行分片就可以了 。
当商户下好了交易订单的时候,需要进行支付这个时候就产生了一笔支付订单。交易订单和支付订单是一对多的关系。当用户进行支付的时候会调用支付引擎,这个时候正常情况下一般会生成支付系统的支付订单。然后支付引擎会调用后续的渠道、结算、记账等系统,系统之间的调用图如下:
如果以支付系统的支付订单的订单号做为分片键时:
。
首先想到的方案可以参考收银台系统,把收银台调用支付引擎看到外部调用。然后添加一张映射表,把收银台生成的支付流水号与支付引擎的支付单号关联起来。当收银台需要查询支付引擎时,可以先通过映射表查询到具体的支付单号,这样就可以进行分片键操作数据源了。这个方案存在一个问题存在以下几个问题:
引入了关联表,添加了系统复杂度进行数据查询的时候会两次查询,先查询映射表,然后再查询支付单 。
那么有没有其它方案呢?答案是肯定的.
我们来看一下收银台、支付引擎其实这两个系统在支付系统中是同一个纬度的。如果收银台的交易订单进行支付的时候,就会在支付引擎当中下一笔支付单。我们可以把交易单与支付单在同一个水平纬度上进行数据库拆分.
什么叫同一个纬度的数据库拆分呢?
其实就是收银台的支付订单进行分库分表之后,这条数据落在数据库里面的哪一个库,哪一张表就一定了。这个时候支付引擎就可以通过这个单号获取到具体的库表信息。这样就可以把支付引擎生成的的订单号带个具体的库表信息。然后在进行分库分表算法定义的时候根据支付引擎生成的订单号中带的库表信息路由到具体的库表中去了。就样就会解决上面的问题,不需要映射表。同时这种方案也会带来以下的问题:
经过讨论决定使用方案二.
。
下面通过 Sharding jdbc 的复合分片简单的模拟代码实现。数据库、表准备:
数据库:- order_0- order_1每个数据库的表:tb_order_0tb_order_1tb_order_2tb_order_3tb_order_4tb_order_5tb_order_6tb_order_7# 逻辑表create table tb_order( trade_master_no varchar(16), pay_order_no varchar(16) ,);# 准备数据# 分库分表规则是前一位代表库,后一位代表表,所以在 order_1.tb_order_1 中添加以下数据insert into tb_order_1 values('11', '11'),
下面是针对订单表的 sharding jdbc 的分库分表配置,数据库连接池使用 Hikari 。分片规则:前一位代表库,后一位代表表。使用交易主单号(trade_master_no) 和 支付单号(pay_order_no) 作为复合分片。当查询条件中只要包含一个查询规则时就会路由到具体库表中.
ComplexShardingJDBCConfig.java 。
@Configurationpublic class ComplexShardingJDBCConfig { @Bean public DataSource getShardingDataSource(HikariCommonConfig commonConfig) throws SQLException { ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); shardingRuleConfig.getTableRuleConfigs().add(getShardingMessageTableRuleConfiguration()); Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("order_0", createDataSource(datasourceOne(commonConfig))); dataSourceMap.put("order_1", createDataSource(datasourceTwo(commonConfig))); Properties properties = new Properties(); properties.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(), "true"); return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties); } private TableRuleConfiguration getShardingMessageTableRuleConfiguration() { TableRuleConfiguration shardingMessageConfiguration = new TableRuleConfiguration("tb_order", "order_${0..1}.tb_order_${0..7}"); shardingMessageConfiguration.setDatabaseShardingStrategyConfig(messageDatasourceShardingStrategyConfig()); shardingMessageConfiguration.setTableShardingStrategyConfig(messageTableShardingStrategyConfig()); return shardingMessageConfiguration; } private ComplexShardingStrategyConfiguration messageDatasourceShardingStrategyConfig(){ return new ComplexShardingStrategyConfiguration("trade_master_no,pay_order_no", new OrderDatasourceComplexKeysShardingAlgorithm()); } private ShardingStrategyConfiguration messageTableShardingStrategyConfig() { return new ComplexShardingStrategyConfiguration("trade_master_no,pay_order_no", new OrderTableComplexKeysShardingAlgorithm()); } @Bean @ConfigurationProperties(prefix = "spring.datasource.ds1") public HikariConfig datasourceOne(HikariCommonConfig commonConfig){ HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setMinimumIdle(commonConfig.getMinimumIdle()); hikariConfig.setIdleTimeout(commonConfig.getIdleTimeout()); hikariConfig.setMaximumPoolSize(commonConfig.getMaximumPoolSize()); hikariConfig.setPoolName(commonConfig.getPoolName()); hikariConfig.setMaxLifetime(commonConfig.getMaxLifetime()); hikariConfig.setConnectionTimeout(commonConfig.getConnectionTimeout()); hikariConfig.setConnectionTestQuery(commonConfig.getConnectionTestQuery()); return hikariConfig; } @Bean @ConfigurationProperties(prefix = "spring.datasource.ds2") public HikariConfig datasourceTwo(HikariCommonConfig commonConfig){ HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setMinimumIdle(commonConfig.getMinimumIdle()); hikariConfig.setIdleTimeout(commonConfig.getIdleTimeout()); hikariConfig.setMaximumPoolSize(commonConfig.getMaximumPoolSize()); hikariConfig.setPoolName(commonConfig.getPoolName()); hikariConfig.setMaxLifetime(commonConfig.getMaxLifetime()); hikariConfig.setConnectionTimeout(commonConfig.getConnectionTimeout()); hikariConfig.setConnectionTestQuery(commonConfig.getConnectionTestQuery()); return hikariConfig; } private HikariDataSource createDataSource(HikariConfig hikariConfig) { HikariDataSource sharding = new HikariDataSource(); BeanUtils.copyProperties(hikariConfig, sharding); return sharding; }}
数据库分片规则:
public class OrderDatasourceComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<String> shardingValue) { Map<String, Collection<String>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap(); if(columnNameAndShardingValuesMap.containsKey("trade_master_no")){ Collection<String> tradeMasterNos = columnNameAndShardingValuesMap.get("trade_master_no"); String tradeMasterNo = tradeMasterNos.iterator().next(); String datasourceSuffix = tradeMasterNo.substring(0, 1); for (String availableTargetName : availableTargetNames) { if(availableTargetName.endsWith(datasourceSuffix)){ return Lists.newArrayList(availableTargetName); } } } if(columnNameAndShardingValuesMap.containsKey("pay_order_no")){ Collection<String> payOrderNos = columnNameAndShardingValuesMap.get("pay_order_no"); String payOrderNo = payOrderNos.iterator().next(); String datasourceSuffix = payOrderNo.substring(0, 1); for (String availableTargetName : availableTargetNames) { if(availableTargetName.endsWith(datasourceSuffix)){ return Lists.newArrayList(availableTargetName); } } } throw new UnsupportedOperationException(); }}
数据库中的表分片规则:
public class OrderTableComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<String> shardingValue) { Map<String, Collection<String>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap(); if(columnNameAndShardingValuesMap.containsKey("trade_master_no")){ Collection<String> tradeMasterNos = columnNameAndShardingValuesMap.get("trade_master_no"); String tradeMasterNo = tradeMasterNos.iterator().next(); String datasourceSuffix = tradeMasterNo.substring(1, 2); for (String availableTargetName : availableTargetNames) { if(availableTargetName.endsWith(datasourceSuffix)){ return Lists.newArrayList(availableTargetName); } } } if(columnNameAndShardingValuesMap.containsKey("pay_order_no")){ Collection<String> payOrderNos = columnNameAndShardingValuesMap.get("pay_order_no"); String payOrderNo = payOrderNos.iterator().next(); String datasourceSuffix = payOrderNo.substring(1, 2); for (String availableTargetName : availableTargetNames) { if(availableTargetName.endsWith(datasourceSuffix)){ return Lists.newArrayList(availableTargetName); } } } throw new UnsupportedOperationException(); }}
这里使用 Mybatis 操作数据源,当然使用其它 ORM 框架操作数据源 sharding jdbc 也是支持的.
public interface OrderMapper { int countByExample(OrderExample example); int deleteByExample(OrderExample example); int insert(Order record); int insertSelective(Order record); List<Order> selectByExample(OrderExample example); int updateByExampleSelective(@Param("record") Order record, @Param("example") OrderExample example); int updateByExample(@Param("record") Order record, @Param("example") OrderExample example);}
通过 Spring boot 定义一个 Controller,使用 Order 对象查询。即可以使用交易单号也可以使用支付单号查询.
@Getter@Setterpublic class Order { private String tradeMasterNo; private String payOrderNo;}@RestController@RequestMapping("order")public class OrderController { @Resource private OrderDao orderDao; @RequestMapping("query") public Order query(@RequestBody Order order) { Order orderInDB = orderDao.queryOrder(order); return orderInDB; }}
由于我们在 sharing jdbc 配置当中配置了数据库查询 SQL,我们只需要观察是不是只打印了一条数据库操作语句就可以判断之前的结论是否正确.
通过 Postman 使用交易单号查询:
控制台打印
然后通过 Postman 使用支付单号查询:
控制台打印:
它们查询都是路由到具体的库表当中,说明我们的方案是可以的.
。
Sharding-JDBC 官网 。
到此这篇关于SpringBoot集成Sharding Jdbc使用复合分片的实践的文章就介绍到这了,更多相关SpringBoot集成Sharding Jdbc复合分片内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/u012410733/article/details/105745735 。
最后此篇关于SpringBoot集成Sharding Jdbc使用复合分片的实践的文章就讲到这里了,如果你想了解更多关于SpringBoot集成Sharding Jdbc使用复合分片的实践的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在使用 Databricks JDBC 驱动程序版本 2.6.22,并尝试升级到 2.6.27。但是,升级后我收到消息说我的 JDBC URL 在尝试连接时无效。这些 JDBC URL 与旧版本
似乎JDBC Spec没有详细说明数据源连接池中alive or idle connections的准确含义。它只是具体实现吗? DBCP2如何或 HikariCP实际检查连接状态? 下面没有事件事务
在“XPages 扩展库”一书中,第 12 章,第 409 页有一个 JDBC 连接文件的例子: org.apache.derby.jdbc.EmbeddedDriver jdbc:
谁能告诉我 jdbc 是如何工作的?它如何设法与 DBMS 通信?因为 DBMS 可能是用其他编程语言编写的。 最佳答案 与数据库的通信由 JDBC 驱动程序处理,这些驱动程序可以使用各种策略与数据库
我想知道是否有人可以帮助我解决这个问题。我在尝试使用 Spring JDBC 编写代码时遇到了一个问题。当我运行服务器时,我收到了标题中提到的消息。我google了一下,有人说你应该导入ojdbc.j
我只是想运行一个示例 hivejdbc 客户端程序,但它给我一个内存不足的错误。 import java.sql.SQLException; import java.sql.Connection; i
我需要将 Google Spreadsheet 与 JasperReports Server 一起使用,为此我需要一个用于 Google Spreadsheet 的 JDBC 连接器。 我找到了这个
我需要将大量行(最多 100,000 行)插入到 6 个不同的 DB2 表中。我正在使用 Java JDBC 来完成它。我想在单个数据库事务中完成所有操作,以便在遇到任何问题时可以回滚整个操作。在某处
再次为自己是 Jmeter 新手道歉——我对 JDBC 请求有点困惑——我在过去的 3 个小时里浏览了这个网站上的帖子——但我找不到任何相关的东西(除非我我错过了一些东西)。 我的环境:Jmeter
我们正在创建一个带有 MySQL 后端的 XPages 应用程序。应用程序将被多个客户使用。每个都有自己的 NSF 数据库和相应的 MySQL 数据库。每个客户都有自己的 MySQL 用户名。我们正在
昨天我遇到了一个大问题。在我当前的项目中,我使用 Oracle 的 JDBC 的 ojdbc6 实现进行连接,但我还需要处理例如 oracle 8 数据库,这对于这个 JAR 是完全不可能的。 你会说
这个问题在这里已经有了答案: Closing JDBC Connections in Pool (3 个答案) 关闭 2 年前。 假设我有以下代码 DataSource source = (Data
我有 Informix 数据库,时间戳字段定义为 YEAR TO SECOND。 当我使用 JDBC rs.getString(column) 显示此字段时,它使用带毫秒的格式,因此此字段如下所示:
看完本教程之后; https://www.youtube.com/watch?v=ZnI_rlrei1s 我正在尝试使用logstash和jdbc获取我的本地主机mysql(使用laravel val
有人给我小费。 { "type": "jdbc", "jdbc": { "driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver"
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我正在尝试从mysql表中将1600万个文档(47gb)索引为elasticsearch索引。我正在使用jparante's elasticsearch jdbc river执行此操作。但是,在创建河
我正在尝试使用JDBC河将我的MySQL数据库复制到我的ElasticSearch索引中。 但是,每当我启动服务器时,与MySQL表的count(*)相比,创建的文档数量就增加了一倍。我通过清空索引并
使用新的logstash jdbc 连接器: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-jdbc.html后续的
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我是一名优秀的程序员,十分优秀!