当前位置: 代码网 > it编程>数据库>MsSqlserver > SQL实现读写分离的分配的几种方式

SQL实现读写分离的分配的几种方式

2025年04月24日 MsSqlserver 我要评论
读写分离的分配,即如何在应用程序中将读操作和写操作路由到不同的数据库实例,可以通过几种不同的方法来实现。这些方法可以在应用程序层、数据库层或使用中间件来完成。以下是几种常见的实现方法:应用程序层实现在

读写分离的分配,即如何在应用程序中将读操作和写操作路由到不同的数据库实例,可以通过几种不同的方法来实现。这些方法可以在应用程序层、数据库层或使用中间件来完成。以下是几种常见的实现方法:

应用程序层实现

在应用程序层实现读写分离,通常通过配置多个数据源并在代码中显式地选择适当的数据源。使用 aop(面向切面编程)来自动选择数据源是一种常见的方法。

具体实现步骤

  • 配置多数据源:配置一个主数据源(用于写操作)和多个从数据源(用于读操作)。
  • 实现路由逻辑:通过 aop 或其他方式在代码中选择适当的数据源。
  • 使用自定义注解:标记需要路由到不同数据源的方法。

以下是详细的实现示例:

配置文件

在 application.yml 中配置主库和从库的信息。

# application.yml
spring:
  datasource:
    master:
      url: jdbc:mysql://master-db:3306/mydb
      username: root
      password: root
    slaves:
      - url: jdbc:mysql://slave-db1:3306/mydb
        username: root
        password: root
      - url: jdbc:mysql://slave-db2:3306/mydb
        username: root
        password: root

数据源配置

import com.zaxxer.hikari.hikaridatasource;
import org.springframework.beans.factory.annotation.autowired;
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.lookup.abstractroutingdatasource;

import javax.sql.datasource;
import java.util.hashmap;
import java.util.map;

@configuration
public class datasourceconfig {

    @autowired
    private masterdatasourceproperties masterproperties;

    @autowired
    private slavedatasourceproperties slaveproperties;

    @bean
    @primary
    public datasource datasource() {
        abstractroutingdatasource routingdatasource = new replicationroutingdatasource();

        hikaridatasource masterdatasource = new hikaridatasource();
        masterdatasource.setjdbcurl(masterproperties.geturl());
        masterdatasource.setusername(masterproperties.getusername());
        masterdatasource.setpassword(masterproperties.getpassword());

        map<object, object> targetdatasources = new hashmap<>();
        targetdatasources.put("master", masterdatasource);

        for (int i = 0; i < slaveproperties.getslaves().size(); i++) {
            slaveproperties slave = slaveproperties.getslaves().get(i);
            hikaridatasource slavedatasource = new hikaridatasource();
            slavedatasource.setjdbcurl(slave.geturl());
            slavedatasource.setusername(slave.getusername());
            slavedatasource.setpassword(slave.getpassword());
            targetdatasources.put("slave" + i, slavedatasource);
        }

        routingdatasource.settargetdatasources(targetdatasources);
        routingdatasource.setdefaulttargetdatasource(masterdatasource);

        return routingdatasource;
    }
}

路由数据源

import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;

public class replicationroutingdatasource extends abstractroutingdatasource {

    private static final threadlocal<string> contextholder = new threadlocal<>();

    public static void setdatasourcetype(string datasourcetype) {
        contextholder.set(datasourcetype);
    }

    public static void cleardatasourcetype() {
        contextholder.remove();
    }

    @override
    protected object determinecurrentlookupkey() {
        return contextholder.get();
    }
}

数据源选择器

import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.before;
import org.springframework.stereotype.component;

@aspect
@component
public class datasourceaspect {

    @before("@annotation(com.example.annotation.master)")
    public void setwritedatasourcetype() {
        replicationroutingdatasource.setdatasourcetype("master");
    }

    @before("@annotation(com.example.annotation.slave) || execution(* com.example.service..*.find*(..))")
    public void setreaddatasourcetype() {
        replicationroutingdatasource.setdatasourcetype("slave0"); // 可实现负载均衡策略
    }
}

自定义注解

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface master {
}

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface slave {
}

示例服务

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import org.springframework.transaction.annotation.transactional;

@service
public class userservice {

    @autowired
    private userrepository userrepository;

    @master
    @transactional
    public void saveuser(user user) {
        userrepository.save(user);
    }

    @slave
    public user finduserbyid(long id) {
        return userrepository.findbyid(id).orelse(null);
    }
}

使用中间件

使用中间件来实现读写分离也是一种常见的方法。中间件通常位于应用程序和数据库之间,负责根据操作类型将请求路由到适当的数据库实例。常见的中间件包括 mysql 的 proxysql 和 mariadb 的 maxscale。

proxysql 示例配置

  • 安装 proxysql:可以通过包管理器安装 proxysql。
  • 配置 proxysql:在 proxysql.cnf 文件中配置主从数据库。
datadir="/var/lib/proxysql"

admin_variables=
{
    admin_credentials="admin:admin"
    mysql_ifaces="0.0.0.0:6032"
}

mysql_variables=
{
    threads=4
    max_connections=1024
}

mysql_servers =
(
    { address="master-db", port=3306, hostgroup=0, max_connections=1000, weight=1 },
    { address="slave-db1", port=3306, hostgroup=1, max_connections=1000, weight=1 },
    { address="slave-db2", port=3306, hostgroup=1, max_connections=1000, weight=1 }
)

mysql_users =
(
    { username="proxyuser", password="proxypassword", default_hostgroup=0, transaction_persistent=1 }
)

mysql_query_rules =
(
    { rule_id=1, match_pattern="^select", destination_hostgroup=1, apply=1 }
)
  • 启动 proxysql:使用 systemctl 或其他方式启动 proxysql。
systemctl start proxysql

数据库层实现

有些数据库本身提供了读写分离的功能。例如,mysql 的复制机制允许配置一个主数据库和多个从数据库,然后通过连接池或驱动程序实现读写分离。

总结

读写分离的实现方法有多种,可以根据具体需求和技术栈选择适合的方法。在应用程序层实现读写分离较为灵活,可以精细控制读写操作的路由逻辑;使用中间件实现读写分离则可以简化应用程序的逻辑,但需要额外维护中间件的配置和管理;在数据库层实现读写分离可以利用数据库本身的功能,减少对应用程序的改动。

到此这篇关于sql实现读写分离的分配的几种方式的文章就介绍到这了,更多相关sql 读写分离分配内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com