sharding-JDBC 实现读写分离

需求

  1. 一主两从,做读写分离。
  2. 多个从库之间实现负载均衡。
  3. 可手动强制部分读请求到主库上。(因为主从同步有延迟,对实时性要求高的系统,可以将部分读请求也走主库)

本次不讨论 MySQL如何配置主从同步相关问题

库表SQL

-- 主库
CREATE DATABASE `master`;

CREATE TABLE `t_order` (
  `order_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `business_id` int(4) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `t_order` VALUES (1,1,112);

-- 从库1
CREATE DATABASE `slave1` ; 
CREATE TABLE `t_order` (
  `order_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `business_id` int(4) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

INSERT INTO `t_order` VALUES (2,2,112);

-- 从库2
CREATE DATABASE `slave2` ; 
CREATE TABLE `t_order` (
  `order_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `business_id` int(4) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `t_order` VALUES (3,3,112);

pom.xml

<!-- https://mvnrepository.com/artifact/io.shardingjdbc/sharding-jdbc-core -->
<dependency>
    <groupId>io.shardingjdbc</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>2.0.0.M2</version>
</dependency>
<dependency>
    <groupId>io.shardingjdbc</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>2.0.0.M2</version>
</dependency>

spring配置文件

<bean id="master" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
      destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="${jdbc.url.master}"></property>
    <property name="username" value="${jdbc.username.master}"></property>
    <property name="password" value="${jdbc.password.master}"></property>
    <property name="maxActive" value="100"/>
    <property name="initialSize" value="10"/>
    <property name="maxWait" value="60000"/>
    <property name="minIdle" value="5"/>
</bean>

<bean id="slave1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
      destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="${jdbc.url.slave1}"></property>
    <property name="username" value="${jdbc.username.slave1}"></property>
    <property name="password" value="${jdbc.password.slave1}"></property>
    <property name="maxActive" value="100"/>
    <property name="initialSize" value="10"/>
    <property name="maxWait" value="60000"/>
    <property name="minIdle" value="5"/>
</bean>

<bean id="slave2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
      destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="${jdbc.url.slave2}"></property>
    <property name="username" value="${jdbc.username.slave2}"></property>
    <property name="password" value="${jdbc.password.slave2}"></property>
    <property name="maxActive" value="100"/>
    <property name="initialSize" value="10"/>
    <property name="maxWait" value="60000"/>
    <property name="minIdle" value="5"/>
</bean>

<bean id="randomStrategy" class="io.shardingjdbc.core.api.algorithm.masterslave.RandomMasterSlaveLoadBalanceAlgorithm" />

<master-slave:data-source id="shardingDataSource" master-data-source-name="master" slave-data-source-names="slave1,slave2" strategy-ref="randomStrategy" />

单测

写:

    @Test
    public void insert() throws Exception {

        Order record = new Order();
        record.setBusinessId(112);
        record.setUserId(111);
        record.setOrderId(12212121);

        int result = orderMapper.insertSelective(record) ;

        System.out.println( result > 0 ? "插入成功" : "插入失败");
    }

运行结果:
758447-20171117203227249-1501966055.png

查:
slave1 只有1条数据,主键order_id = 2 ; slave2 也只有1条数据,主键order_id = 3 。所以,如果查询到的结果orderId等于1就说明读请求进入到slave1,同理,如果查询出来的orderId等于0 就说明读请求进入到slave2。

 public void selectByExample3() throws Exception {

        final int[] slave1 = {0};
        final int[] slave2 = {0};

        for (int i = 0; i < 100; i++) {
            ((Runnable) () -> {
                OrderExample example = new OrderExample();
                example.createCriteria().andBusinessIdEqualTo(112);

                List<Order> orderList = orderMapper.selectByExample(example);

                if (orderList.get(0).getOrderId() == 2) {
                    System.out.printf("读到slave1  读到的数据是{}", JSONObject.toJSONString(orderList.get(0)));
                    slave1[0]++;
                } else if (orderList.get(0).getOrderId() == 3) {
                    System.out.printf("读到slave2  读到的数据是{}",                             JSONObject.toJSONString(orderList.get(0)));
                    slave2[0]++;
                }
                System.out.println(JSONObject.toJSONString(orderList));
            }).run();
        }

        System.out.println("+++++++++++++++++++++++++++++++++++++++");
        System.out.println("+++++++++++++++++++++++++++++++++++++++");
        System.out.println("slave1读到的次数-->" + slave1[0]);
        System.out.println("slave2读到的次数-->" + slave2[0]);
        System.out.println("+++++++++++++++++++++++++++++++++++++++");
        System.out.println("+++++++++++++++++++++++++++++++++++++++");
    }

运行截图:

758447-20171117093212359-350344877.png

强制路由

通常做读写分离,都会遇到的一个问题就是主从同步延迟。有时,为了简单解决主从同步问题,我们会想强制部分读请求到主库上,而非从库上。

HintManager 分片键值管理器

官方文档的解释:
基于暗示(Hint)的分片键值管理器

但是对于读写分离这种形式的强制路由 , 其实官方文档说的几个方法都不适用. 我们可使用hintManager.setMasterRouteOnly() .

单测

@Test
public void HintManagerTest() {

    HintManager hintManager = HintManager.getInstance() ;

    hintManager.setMasterRouteOnly();

    OrderExample example = new OrderExample();
    example.createCriteria().andBusinessIdEqualTo(112);

    List<Order> orderList = orderMapper.selectByExample(example);

    System.out.println(JSONObject.toJSONString(orderList));

    hintManager.close();
    
}

转载于:https://www.cnblogs.com/boothsun/p/7853526.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ShardingSphere:SpringBoot2+MybatisPlus+读写分离+分库分表课程目标快速的掌握读写分离+分表的实战,即插即用适用人群IT从业人员,开发人员,Java从业者,互联网从业者,性能调优人群课程简介ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。它由Sharding-JDBCSharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。 Sharding-JDBCSharding-JDBCSharding-Sphere的第一个产品,也是Sharding-Sphere的前身,是当当网开源的一个产品。定位为轻量级的Java框架,在JavaJDBC层提供额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。Sharding-JDBC可以通过Java,YAML,Spring命名空间和Spring Boot Starter四种方式配置,开发者可根据场景选择适合的配置方式。课程特色 本章节以尽量短的时间,为使用者提供最简单的ShardingSphere的快速入门。课程说明该课程属于系列课程,分为读写分离,分库不分表,不分库分表,分库分表,读写分离+分库分表共5个回合。本课程属于其中一个回合,请各位小哥哥们注意,课程的标题哦~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值