1 -【 MySQL 集群 】- 5 Sharding-Jdbc 实现读写分离

1 Sharding-Jdbc 介绍

Sharding-Jdbc3.0 后改名为 Shardingsphere

它由 Sharding-JDBCSharding-ProxySharding-Sidecar(计划中)这3款相互独立的产品组成。他们均提供标准化的 数据分片分布式事务数据库治理 功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。

Sharding-Sphere 定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。

应用场景:

  • 数据库读写分离
  • 数据库分表分库

Sharding-Jdbc官方网址:http://shardingsphere.io/index_zh.html

2 Sharding-JdbcMyCat 区别

MyCat 是一个基于第三方应用中间件数据库代理框架,客户端所有的 jdbc 请求都必须要先交给 MyCat,再由 MyCat 转发到具体的真实服务器中。

Sharding-Jdbc 是一个 Jar 形式,在本地应用层重写 Jdbc 原生的方法,实现数据库分片形式。

MyCat 属于服务器端数据库中间件,而 Sharding-Jdbc 是一个 本地数据库中间件框架

从设计理念上看确实有一定的相似性。主要流程都是 SQL 解析 -> SQL 路由 -> SQL 改写 -> SQL 执行 -> 结果归并。但架构设计上是不同的。Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库,而 Sharding-JDBC 是基于 JDBC 的扩展,是以 jar 包的形式提供轻量级服务的。

这也就是之前在微服务中学习的 SpringCloud RibbonNginx 区别。

3 Sharding-Jdbc 实现读写分离

Sharding-Jdbc 实现读写分离原理,非常容易。只需要在项目中集成主和从的数据源,Sharding-Jdbc 自动根据 DMLDQL 语句类型连接主或者从数据源。

注意: Sharding-Jdbc 只是实现连接主或者从数据源,不会实现主从复制功能,需要自己配置数据库自带主从复制方式。

查看 MasterSlaveDataSource 即可查看该类 getDataSource 方法获取当前数据源名称

  • DQL:数据查询语言 DQL 基本结构是由 SELECT 子句,FROM 子句,WHERE 子句组成的查询块:

    SELECT <字段名表> FROM <表或视图名> WHERE <查询条件>
    
  • DML:数据操纵语言 DML 主要有三种形式:

    • 插入:INSERT
    • 更新:UPDATE
    • 删除:DELETE
    • 创建:CREATE

Sharding-Jdbc 只是单纯实现判断 DML 或者是 DQL 语句

4 SpringBoot 整合 Sharding-Jdbc

4.1 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.23</version>
</dependency>
<dependency>
    <groupId>io.shardingjdbc</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>2.0.3</version>
</dependency>

4.2 application.yml

### 服务启动端口号
server:
  port: 8400
mybatis-plus:
  #  mapper-locations: classpath*:/mapper/*.xml
  global-config:
    db-config:
      column-underline: true

#shardingjdbc配置
sharding:
  jdbc:
    data-sources:
      ###配置第一个从数据库
      ds_slave_0:
        jdbc-url: jdbc:mysql://192.168.153.101:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: 123456
      ###主数据库配置
      ds_master:
        jdbc-url: jdbc:mysql://192.168.153.102:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: 123456
    ###配置读写分离
    master-slave-rule:
      ###配置从库选择策略,提供轮询与随机,这里选择用轮询
      load-balance-algorithm-type: round_robin
      ####指定从数据库
      slave-data-source-names: ds_slave_0
      name: ds_ms
      ####指定主数据库
      master-data-source-name: ds_master

### 服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-snow-mysql

### 服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8100/eureka

### 问题:微信端口号是8200,会员端口号为8300?
###      目的是为了以后做集群方便分辨,例如:微信集群 82001、82002;会员集群:83001、83002。

### swagger相关配置
swagger:
  base-package: com.snow.mysql.service                     # 扫描包的范围
  title: SpringCloud2.x构建微服务项目-会员服务接口           # 标题
  description: 该项目“基于SpringCloud2.x构建微服务项目”。    # 描述
  version: 1.1                                              # 版本
  terms-of-service-url: www.csdn.shop                      # 联系网址
  contact:
    name: yang                                             # 姓名
    email: [email protected]                                # 邮箱

4.3 启动项

package com.snow.mysql;

import com.spring4all.swagger.EnableSwagger2Doc;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author yang-windows
 * @Title:
 * @Package
 * @Description:
 * @date 2020/3/29 20:10
 */
@SpringBootApplication
@MapperScan(basePackages = "com.snow.mysql.mapper")
@EnableEurekaClient
@EnableSwagger2Doc
public class AppMysql {

    public static void main(String[] args) {
        SpringApplication.run(AppMysql.class);
    }
}

4.4 实体类

package com.snow.api.entity.mysql;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class User {

    private Long id;

    private String name;
}

4.5 mapper

package com.snow.mysql.mapper;

import com.snow.api.entity.mysql.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @author yang-windows
 * @Title: snow-parent
 * @Package com.snow.mysql.mapper
 * @Description: UserMapper
 * @date 2020/3/29 20:17
 */
public interface UserMapper {

    @Select("SELECT * FROM user")
    public List<User> findUser();

    @Insert("insert into user(name) values (#{name}); ")
    public int insertUser(@Param("name")String name);

}

4.6 service

package com.snow.mysql.service;

import com.snow.api.entity.mysql.User;
import com.snow.mysql.mapper.UserMapper;
import com.snow.service.api.mysql.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author yang-windows
 * @Title:
 * @Package
 * @Description:
 * @date 2020/3/29 20:13
 */
@RestController
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findUser() {
        return userMapper.findUser();
    }

    @Override
    public void insertUser(String name) {
        int i = userMapper.insertUser(name);
        System.out.println("i === " + i);
    }

}

4.7 Config 配置信息

package com.snow.mysql.config;

import com.zaxxer.hikari.HikariDataSource;
import io.shardingjdbc.core.api.config.MasterSlaveRuleConfiguration;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.HashMap;
import java.util.Map;

/**
 * @author yang-windows
 * @Title: snow-parent
 * @Package com.snow.mysql.config
 * @Description: TODO
 * @date 2020/3/30 23:36
 */
@Data
@ConfigurationProperties(prefix = "sharding.jdbc")
public class ShardingMasterSlaveConfig {

    // 存放本地多个数据源
    private Map<String, HikariDataSource> dataSources = new HashMap<>();

    private MasterSlaveRuleConfiguration masterSlaveRule;
}

package com.snow.mysql.config;

import java.sql.SQLException;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.collect.Maps;

import io.shardingjdbc.core.api.MasterSlaveDataSourceFactory;
import lombok.extern.log4j.Log4j2;

/**
 * @author yang-windows
 * @Title: snow-parent
 * @Package com.snow.mysql.config
 * @Description: TODO
 * @date 2020/3/30 23:37
 */
@Configuration
@EnableConfigurationProperties(ShardingMasterSlaveConfig.class)
@Log4j2
// 读取ds_master主数据源和读写分离配置
@ConditionalOnProperty({ "sharding.jdbc.data-sources.ds_master.jdbc-url",
        "sharding.jdbc.master-slave-rule.master-data-source-name" })
public class ShardingDataSourceConfig {

    @Autowired
    private ShardingMasterSlaveConfig shardingMasterSlaveConfig;

    @Bean
    public DataSource masterSlaveDataSource() throws SQLException {
        final Map<String, DataSource> dataSourceMap = Maps.newHashMap();
        dataSourceMap.putAll(shardingMasterSlaveConfig.getDataSources());
        final Map<String, Object> newHashMap = Maps.newHashMap();
        // 创建 MasterSlave数据源
        DataSource dataSource = MasterSlaveDataSourceFactory.createDataSource(dataSourceMap,
                shardingMasterSlaveConfig.getMasterSlaveRule(), newHashMap);
        log.info("masterSlaveDataSource config complete");
        return dataSource;
    }

}

4.8 测试

分别测试查询和插入接口,可以看到分别在对应的数据库查找和插入数据:

在这里插入图片描述

在这里插入图片描述

发布了687 篇原创文章 · 获赞 229 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_42112635/article/details/105211407