【ShardingSphere-JDBC实现读写分离】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

ShardingSphere-JDBC是一个开源的分布式数据库中间件,提供了数据库的分库分表、读写分离、数据分片等功能。它的主要特点包括:

  1. 分库分表:可以将数据按照一定规则分散到不同的数据库或表中,实现数据的水平切分,提高数据库的扩展性和性能。
  2. 读写分离:可以根据需求将读操作和写操作分发到不同的数据库节点,实现读写分离,提高数据库的负载能力。
  3. 数据分片:可以按照某种特定的规则将数据分散到不同的数据库节点上,并通过统一的接口对外提供访问,实现数据的分布式存储。
  4. 支持多种数据库:ShardingSphere-JDBC支持多种主流数据库,如MySQL、Oracle、SQL Server等,可以方便地与现有的数据库系统集成。
  5. 兼容性强:ShardingSphere-JDBC完全兼容现有的JDBC接口和SQL语法,使用方便,对现有的应用程序无需修改或重新编写。
  6. 高性能:ShardingSphere-JDBC经过优化,具有较好的性能表现,可以提供高并发、低延迟的数据库访问能力。

总之,ShardingSphere-JDBC是一个功能强大的分布式数据库中间件,可以帮助开发人员简化数据库架构设计、提高数据库性能和扩展性,是构建高可用、高性能的分布式系统的理想选择。


提示:以下是本篇文章正文内容,下面案例可供参考

一、内部结构

官方文档链接:ShardingSphere-JDBC
在这里插入图片描述
结构描述

二、配置及使用示例

1.依赖包配置

代码如下(示例):

        <!-- Sharding-JDBC核心依赖 -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>4.0.1</version>
        </dependency>

2.基于Spring boot的规则配置,使用JAVA配置

代码如下(示例):

#sharding.jdbc(读写分离)数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=master,slave0,slave1
#数据库连接池类名称
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名(主库)
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://172.16.xxx.xx1:3306/test_data?verifyServerCertificate=false&useSSL=false&requireSSL=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=utf8
spring.shardingsphere.datasource.master.username=gfh_dev_1
spring.shardingsphere.datasource.master.password=123456
#以下配置可根据具体情况选择和修改(每个数据源都可配置,该示例从库省略)
spring.shardingsphere.datasource.master.maxActive=300
spring.shardingsphere.datasource.master.maxWait=10000
spring.shardingsphere.datasource.master.minIdle=5
spring.shardingsphere.datasource.master.initialSize=5
spring.shardingsphere.datasource.master.validationQuery=SELECT 1
spring.shardingsphere.datasource.master.testWhileIdle=true
spring.shardingsphere.datasource.master.timeBetweenEvictionRunsMillis=18800
spring.shardingsphere.datasource.master.minEvictableIdleTimeMillis=300000
spring.shardingsphere.datasource.master.removeAbandoned=true
spring.shardingsphere.datasource.master.removeAbandonedTimeoutMillis=300
spring.shardingsphere.datasource.master.filters=stat

#从库1
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://172.16.xxx.xx2:3306/test_data?verifyServerCertificate=false&useSSL=false&requireSSL=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=utf8
spring.shardingsphere.datasource.slave0.username=gfh_dev_2
spring.shardingsphere.datasource.slave0.password=123456

#从库2
spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.url=jdbc:mysql://172.16.xxx.xx3:3306/test_data?verifyServerCertificate=false&useSSL=false&requireSSL=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=utf8
spring.shardingsphere.datasource.slave1.username=gfh_dev_3
spring.shardingsphere.datasource.slave1.password=123456

#从库负载均衡算法类型,可选值:(轮询)round_robin,(随机)random。若`load-balance-algorithm-class-name`存在则忽略该配置
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
spring.shardingsphere.masterslave.name=dataSource
#主库数据源名称
spring.shardingsphere.masterslave.master-data-source-name=master
#从库数据源名称列表
spring.shardingsphere.masterslave.slave-data-source-names=slave0,slave1
#是否开启SQL显示,默认值: false
spring.shardingsphere.props.sql.show=true

3.使用java代码引用配置文件(则无需其他依赖包)

加载数据源

import com.alibaba.druid.pool.DruidDataSource;
import com.zgf.gongfuhui.backendapi.utils.EncryptUtils;

@SuppressWarnings("serial")
public class SecurityDataSource extends DruidDataSource {

    public SecurityDataSource() {
        super();
    }
    
    @Override
    public void setPassword(String password) {
        // 
        String decryptPwd = EncryptUtils.decryptDsPwd(password);
        super.setPassword(decryptPwd);
    }
}

调用数据源进行读写分离配置

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.shardingsphere.api.config.masterslave.LoadBalanceStrategyConfiguration;
import org.apache.shardingsphere.api.config.masterslave.MasterSlaveRuleConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.MasterSlaveDataSourceFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: 123
 * @Description: shardingJdbc读写分离配置文件
 * @Date: 2020/5/21 12:12
 */
@Configuration
@MapperScan(basePackages = {"com.zgf.gongfuhui.backendapi.mapper", "com.zgf.gongfuhui.backendapi.commonMapper"},
        sqlSessionTemplateRef = "shardingSqlSessionTemplate")
public class DataSourceConfigRation {
    @Value("${spring.shardingsphere.masterslave.name}")
    private String name;
    @Value("${spring.shardingsphere.masterslave.master-data-source-name}")
    private String masterDataSourceName;
    @Value("${spring.shardingsphere.masterslave.slave-data-source-names}")
    private String slaveDataSourceNames;
    @Value("${spring.shardingsphere.masterslave.load-balance-algorithm-type}")
    private String type;
    @Value("${spring.shardingsphere.props.sql.show}")
    private boolean sqlShow;

    @Bean(name = "master")
    @ConfigurationProperties(prefix = "spring.shardingsphere.datasource.master")
    public DataSource master() {

        return new SecurityDataSource();
    }

    @Bean(name = "slave0")
    @ConfigurationProperties(prefix = "spring.shardingsphere.datasource.slave0")
    public DataSource slave0() {
        return new SecurityDataSource();
    }

    @Bean(name = "slave1")
    @ConfigurationProperties(prefix = "spring.shardingsphere.datasource.slave1")
    public DataSource slave1() {
        return new SecurityDataSource();
    }

    @Bean(name = "dataSourceMap")
    public Map<String, DataSource> dataSourceMap(@Qualifier("master") DataSource master,
                                                 @Qualifier("slave0") DataSource slave0, @Qualifier("slave1") DataSource slave1) {
        // 设置分库映射
        Map<String, DataSource> dataSourceMap = new LinkedHashMap<>();
        dataSourceMap.put("master", master);
        dataSourceMap.put("slave0", slave0);
        dataSourceMap.put("slave1", slave1);
        // 设置默认库,两个库以上时必须设置默认库。默认库的数据源名称必须是dataSourceMap的key之一
        return dataSourceMap;
    }

    @Bean(name = "shardingDataSource")
    public DataSource getShardingDataSource(
            @Qualifier("dataSourceMap") Map<String, DataSource> dataSourceMap) throws SQLException {
        Properties properties = new Properties();
        properties.put("sql.show", sqlShow);

        LoadBalanceStrategyConfiguration loadBalanceStrategyConfiguration = new LoadBalanceStrategyConfiguration(type);
        MasterSlaveRuleConfiguration masterSlaveRuleConfiguration = new
                MasterSlaveRuleConfiguration(name, masterDataSourceName,
                Arrays.asList(slaveDataSourceNames.split(",")),
                loadBalanceStrategyConfiguration);

        //获取数据源对象
        return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, masterSlaveRuleConfiguration, properties);
    }

    /**
     * 需要手动配置事务管理器
     *
     * @param shardingDataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager transactitonManager(
            @Qualifier("shardingDataSource") DataSource shardingDataSource) {
        return new DataSourceTransactionManager(shardingDataSource);
    }

    @Primary
    @Bean(name = "shardingSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("shardingDataSource") DataSource shardingDataSource)
            throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(shardingDataSource);
        return sqlSessionFactoryBean.getObject();
    }

    @Primary
    @Bean(name = "shardingSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(
            @Qualifier("shardingSqlSessionFactory") SqlSessionFactory shardingSqlSessionFactory) {
        return new SqlSessionTemplate(shardingSqlSessionFactory);
    }
}

三、基于暗示(Hint)的强制主库路由

1.简介

ShardingSphere使用ThreadLocal管理分片键值进行Hint强制路由。可以通过编程的方式向HintManager中添加分片值,该分片值仅在当前线程内生效。 Hint方式主要使用场景:
1.分片字段不存在SQL中、数据库表结构中,而存在于外部业务逻辑。
2.强制在主库进行某些数据操作。

2.获取HintManager设置主库路由

使用hintManager.setMasterRouteOnly设置主库路由。清除分片键值:分片键值保存在ThreadLocal中,所以需要在操作结束时调用hintManager.close()来清除ThreadLocal中的内容。hintManager实现了AutoCloseable接口,可推荐使用try with resource自动关闭

3. 示例

官方完整代码示例

String sql = "SELECT * FROM t_order";
try (
        HintManager hintManager = HintManager.getInstance();
        Connection conn = dataSource.getConnection();
        PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
    hintManager.setMasterRouteOnly();
    try (ResultSet rs = preparedStatement.executeQuery()) {
        while (rs.next()) {
            // ...
        }
    }
}

可在API头部使用

@RequestMapping(value = "/order/makeOrder", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
public ResponseObject makeOrder() {
    try {
			// 强制路由到主库
			HintManager hintManager = HintManager.getInstance();
			hintManager.setMasterRouteOnly();
			
			// 其他逻辑代码块
			....
			
			
		} finally {
            // 在finally中强制路由器被释放
            hintManager.close();
        }
}

总结

使用ShardingSphere-JDBC实现读写分离,需要进行以下步骤:

  1. 配置数据源:首先,需要配置多个数据源,分别用于处理读操作和写操作。可以使用ShardingSphere提供的多种数据源类型,例如Master-Slave数据源、Sharding数据源等。

  2. 配置数据源路由:接下来,需要配置数据源的路由规则,以确定读操作和写操作分别路由到哪些数据源上。可以根据业务需求进行灵活的配置,例如根据SQL语句中的表名或列名进行路由。

  3. 配置读写分离:在配置数据源路由的基础上,还需要配置读写分离规则,将读操作和写操作分别路由到不同的数据源上。可以根据业务需求进行灵活的配置,例如使用主从同步来实现读写分离。

  4. 配置数据库连接池:最后,需要配置数据库连接池,以提高系统的性能和可扩展性。可以使用ShardingSphere提供的多种连接池技术,例如Druid、HikariCP等。

总结起来,使用ShardingSphere-JDBC实现读写分离需要配置数据源、数据源路由、读写分离规则和数据库连接池。通过合理的配置和路由规则,可以将读操作和写操作分别路由到不同的数据库节点上,以提高系统的性能和可扩展性。同时,使用数据库连接池可以进一步提高系统的性能和可靠性。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值