亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SQL實(shí)現(xiàn)讀寫(xiě)分離的分配的幾種方式

 更新時(shí)間:2025年04月24日 10:28:58   作者:灰_灰丶灰  
讀寫(xiě)分離的分配,即如何在應(yīng)用程序中將讀操作和寫(xiě)操作路由到不同的數(shù)據(jù)庫(kù)實(shí)例,可以通過(guò)幾種不同的方法來(lái)實(shí)現(xiàn),下面就來(lái)介紹SQL實(shí)現(xiàn)讀寫(xiě)分離的分配的幾種方式,感興趣的可以了解一下

讀寫(xiě)分離的分配,即如何在應(yīng)用程序中將讀操作和寫(xiě)操作路由到不同的數(shù)據(jù)庫(kù)實(shí)例,可以通過(guò)幾種不同的方法來(lái)實(shí)現(xiàn)。這些方法可以在應(yīng)用程序?qū)?、?shù)據(jù)庫(kù)層或使用中間件來(lái)完成。以下是幾種常見(jiàn)的實(shí)現(xiàn)方法:

應(yīng)用程序?qū)訉?shí)現(xiàn)

在應(yīng)用程序?qū)訉?shí)現(xiàn)讀寫(xiě)分離,通常通過(guò)配置多個(gè)數(shù)據(jù)源并在代碼中顯式地選擇適當(dāng)?shù)臄?shù)據(jù)源。使用 AOP(面向切面編程)來(lái)自動(dòng)選擇數(shù)據(jù)源是一種常見(jiàn)的方法。

具體實(shí)現(xiàn)步驟

  • 配置多數(shù)據(jù)源:配置一個(gè)主數(shù)據(jù)源(用于寫(xiě)操作)和多個(gè)從數(shù)據(jù)源(用于讀操作)。
  • 實(shí)現(xiàn)路由邏輯:通過(guò) AOP 或其他方式在代碼中選擇適當(dāng)?shù)臄?shù)據(jù)源。
  • 使用自定義注解:標(biāo)記需要路由到不同數(shù)據(jù)源的方法。

以下是詳細(xì)的實(shí)現(xiàn)示例:

配置文件

在 application.yml 中配置主庫(kù)和從庫(kù)的信息。

# 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

數(shù)據(jù)源配置

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;
    }
}

路由數(shù)據(jù)源

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();
    }
}

數(shù)據(jù)源選擇器

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"); // 可實(shí)現(xiàn)負(fù)載均衡策略
    }
}

自定義注解

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 {
}

示例服務(wù)

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);
    }
}

使用中間件

使用中間件來(lái)實(shí)現(xiàn)讀寫(xiě)分離也是一種常見(jiàn)的方法。中間件通常位于應(yīng)用程序和數(shù)據(jù)庫(kù)之間,負(fù)責(zé)根據(jù)操作類型將請(qǐng)求路由到適當(dāng)?shù)臄?shù)據(jù)庫(kù)實(shí)例。常見(jiàn)的中間件包括 MySQL 的 ProxySQL 和 MariaDB 的 MaxScale。

ProxySQL 示例配置

  • 安裝 ProxySQL:可以通過(guò)包管理器安裝 ProxySQL。
  • 配置 ProxySQL:在 proxysql.cnf 文件中配置主從數(shù)據(jù)庫(kù)。
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 }
)
  • 啟動(dòng) ProxySQL:使用 systemctl 或其他方式啟動(dòng) ProxySQL。
systemctl start proxysql

數(shù)據(jù)庫(kù)層實(shí)現(xiàn)

有些數(shù)據(jù)庫(kù)本身提供了讀寫(xiě)分離的功能。例如,MySQL 的復(fù)制機(jī)制允許配置一個(gè)主數(shù)據(jù)庫(kù)和多個(gè)從數(shù)據(jù)庫(kù),然后通過(guò)連接池或驅(qū)動(dòng)程序?qū)崿F(xiàn)讀寫(xiě)分離。

總結(jié)

讀寫(xiě)分離的實(shí)現(xiàn)方法有多種,可以根據(jù)具體需求和技術(shù)棧選擇適合的方法。在應(yīng)用程序?qū)訉?shí)現(xiàn)讀寫(xiě)分離較為靈活,可以精細(xì)控制讀寫(xiě)操作的路由邏輯;使用中間件實(shí)現(xiàn)讀寫(xiě)分離則可以簡(jiǎn)化應(yīng)用程序的邏輯,但需要額外維護(hù)中間件的配置和管理;在數(shù)據(jù)庫(kù)層實(shí)現(xiàn)讀寫(xiě)分離可以利用數(shù)據(jù)庫(kù)本身的功能,減少對(duì)應(yīng)用程序的改動(dòng)。

到此這篇關(guān)于SQL實(shí)現(xiàn)讀寫(xiě)分離的分配的幾種方式的文章就介紹到這了,更多相關(guān)SQL 讀寫(xiě)分離分配內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論