A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 孤尽 于 2019-2-24 21:41 编辑


SpringBoot使用Sharding-JDBC读写分离

摘要: 本文介绍SpringBoot使用当当Sharding-JDBC进行读写分离。 1.有关Sharding-JDBC 本文还是基于当当网Sharding-Jdbc的依赖,与上一篇使用Sharding-Jdbc进行分库分表依赖一致,并且本文大致内容与上一篇文章相似,建议先查看我的另一篇在查看这篇会简单许多,传送门《SpringBoot使用Sharding-JDBC分库分表》。

本文介绍SpringBoot使用当当Sharding-JDBC进行读写分离。

一.有关Sharding-JDBC

       本文还是基于当当网Sharding-Jdbc的依赖,与上一篇使用Sharding-Jdbc进行分库分表依赖一致,并且本文大致内容与上一篇文章相似,建议先查看我的另一篇在查看这篇会简单许多,传送门:
SpringBoot使用Sharding-JDBC分库分表:https://www.dalaoyang.cn/article/95?spm=a2c4e.11153940.blogcont690021.12.a232195fabQVro
这里需要特殊介绍的是,使用Sharding-JDBC进行读写分离的时候,只允许设置一个主库,从库的话可以设置多个,访问策略的话从源码上看只有两种轮询(ROUND_ROBIN)和随机(RANDOM)。
源码代码如下:
[Java] 纯文本查看 复制代码
package com.dangdang.ddframe.rdb.sharding.api.strategy.slave;

public enum MasterSlaveLoadBalanceStrategyType {
    ROUND_ROBIN(new RoundRobinMasterSlaveLoadBalanceStrategy()),
    RANDOM(new RandomMasterSlaveLoadBalanceStrategy());

    private final MasterSlaveLoadBalanceStrategy strategy;

    public static MasterSlaveLoadBalanceStrategyType getDefaultStrategyType() {
        return ROUND_ROBIN;
    }

    private MasterSlaveLoadBalanceStrategyType(MasterSlaveLoadBalanceStrategy strategy) {
        this.strategy = strategy;
    }

    public MasterSlaveLoadBalanceStrategy getStrategy() {
        return this.strategy;
    }
}

二.本文场景
        由于本地环境并没有使用Mysql主从复制,只是创建了三个库,其中database0作为主库,database1和database2作为从库。主库进行增删改操作,从库进行查询操作,如下图为本文数据库的三个表。
如上图分别是三个数据库中的user表,其中master-user为database0数据库中的user表,salve-user1为database1中的user表,salve-user2为database2中的user表。

三.代码实现
        本文使用SpringBoot2.0.3,SpringData-JPA,Druid连接池,和当当的sharding-jdbc。
3.1 建表SQL
        创建表和数据库的SQL如下所示,这里默认在从库内分别插入了一条数据,name值分别存放dalaoyang1和dalaoyang2便于区分。
[Java] 纯文本查看 复制代码
CREATE DATABASE database0;
USE database0;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`(
    id bigint(64) not null,
    city varchar(20) not null,
    name varchar(20) not null,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE DATABASE database1;
USE database1;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`(
    id bigint(64) not null,
    city varchar(20) not null,
    name varchar(20) not null,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `database1`.`user`(`id`, `city`, `name`) VALUES (101, 'beijing', 'dalaoyang1');

CREATE DATABASE database2;
USE database2;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`(
    id bigint(64) not null,
    city varchar(20) not null,
    name varchar(20) not null,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `database2`.`user`(`id`, `city`, `name`) VALUES (102, 'beijing', 'dalaoyang2');

3.2 依赖文件
        新建项目,依赖文件还是当当的sharding-jdbc-core依赖和druid连接池,完整pom文件代码如下所示。
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dalaoyang</groupId>
    <artifactId>springboot2_shardingjdbc_dxfl</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot2_shardingjdbc_dxfl</name>
    <description>springboot2_shardingjdbc_dxfl</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- sharding-jdbc -->
        <dependency>
            <groupId>com.dangdang</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>1.5.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.3 配置信息
        在配置信息中配置了三个数据库的信息和JPA的简单配置。
[Java] 纯文本查看 复制代码
##Jpa配置
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
##数据库配置
##数据库database0地址
database0.url=jdbc:mysql://localhost:3306/database0?characterEncoding=utf8&useSSL=false
##数据库database0用户名
database0.username=root
##数据库database0密码
database0.password=root
##数据库database0驱动
database0.driverClassName=com.mysql.jdbc.Driver
##数据库database0名称
database0.databaseName=database0

##数据库database1地址
database1.url=jdbc:mysql://localhost:3306/database1?characterEncoding=utf8&useSSL=false
##数据库database1用户名
database1.username=root
##数据库database1密码
database1.password=root
##数据库database1驱动
database1.driverClassName=com.mysql.jdbc.Driver
##数据库database1名称
database1.databaseName=database1

##数据库database2地址
database2.url=jdbc:mysql://localhost:3306/database2?characterEncoding=utf8&useSSL=false
##数据库database1用户名
database2.username=root
##数据库database1密码
database2.password=root
##数据库database1驱动
database2.driverClassName=com.mysql.jdbc.Driver
##数据库database1名称
database2.databaseName=database2
3.4 启动类
        上一篇文章说到在启动类加入了@EnableAutoConfiguration去除数据库自动配置,当时也没太注意,其实可以直接在@SpringBootApplication注解上去除数据库自动配置,剩下的和上一篇一样,使用@EnableTransactionManagement开启事务,使用@EnableConfigurationProperties注解加入配置实体,启动类完整代码如下所示。
[Java] 纯文本查看 复制代码
package com.dalaoyang;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableTransactionManagement(proxyTargetClass = true)
@EnableConfigurationProperties
public class Springboot2ShardingjdbcDxflApplication {

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

}

3.5 实体类和数据库操作层
User实体类。
[Java] 纯文本查看 复制代码
package com.dalaoyang.entity;

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name="user")
@Data
public class User {

    @Id
    private Long id;

    private String city;

    private String name;
}

四.测试4.1 测试主库
使用postman访问http://localhost:8080/save,控制台如图所示。
再次访问,如图。

主键冲突了,其实这是由于插入的时候使用的database0,但是查询使用的是database1和database2,但是我在从库内并没有ID是100的数据,所以JPA判定我为插入,但是数据库内缺有这样的数据。
我们接下来测试一下查询。访问http://localhost:8080/getAll

再次访问,如图。

证明从库的读取是正常的,接下来修改从库的ID为100。然后访问http://localhost:8080/save,查看控制台如图。因为存在了ID为100的数据,所以SQL为修改语句。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马