最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實(shí)現(xiàn)垂直分片的六種策略

 更新時(shí)間:2025年06月19日 08:32:29   作者:風(fēng)象南  
隨著業(yè)務(wù)規(guī)模的不斷擴(kuò)大,單一數(shù)據(jù)庫(kù)架構(gòu)往往難以滿足日益增長(zhǎng)的數(shù)據(jù)量和訪問(wèn)壓力,作為解決方案之一,垂直分片通過(guò)將不同業(yè)務(wù)模塊的數(shù)據(jù)分散到不同的數(shù)據(jù)庫(kù)或?qū)嵗?本文將介紹在SpringBoot環(huán)境下實(shí)現(xiàn)垂直分片的六種策略,需要的朋友可以參考下

一、垂直分片概述

1.1 什么是垂直分片

垂直分片是數(shù)據(jù)庫(kù)分庫(kù)分表的一種方式,它按照業(yè)務(wù)功能或數(shù)據(jù)表將原本在同一個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)拆分到不同的數(shù)據(jù)庫(kù)實(shí)例中。

與水平分片(將同一張表的數(shù)據(jù)按照某種規(guī)則分散到不同庫(kù)或表中)不同,垂直分片主要解決的是業(yè)務(wù)模塊的解耦和單庫(kù)的資源瓶頸問(wèn)題。

1.2 垂直分片的優(yōu)勢(shì)

  • 減輕單庫(kù)壓力:將不同業(yè)務(wù)模塊分散到不同數(shù)據(jù)庫(kù),分散了數(shù)據(jù)庫(kù)負(fù)載
  • 業(yè)務(wù)解耦:不同業(yè)務(wù)模塊的數(shù)據(jù)獨(dú)立存儲(chǔ),便于業(yè)務(wù)模塊的獨(dú)立擴(kuò)展
  • 提高系統(tǒng)可用性:?jiǎn)蝹€(gè)數(shù)據(jù)庫(kù)故障只會(huì)影響部分業(yè)務(wù)模塊
  • 便于維護(hù)和優(yōu)化:可以針對(duì)不同業(yè)務(wù)特點(diǎn)選擇不同的數(shù)據(jù)庫(kù)類型和優(yōu)化策略
  • 權(quán)限隔離:便于進(jìn)行業(yè)務(wù)級(jí)別的數(shù)據(jù)訪問(wèn)權(quán)限控制

1.3 垂直分片的挑戰(zhàn)

  • 分布式事務(wù):跨庫(kù)操作時(shí)需要處理分布式事務(wù)
  • 數(shù)據(jù)一致性:多庫(kù)數(shù)據(jù)同步和一致性保證
  • 跨庫(kù)查詢:涉及多個(gè)業(yè)務(wù)模塊的查詢變得復(fù)雜
  • 開發(fā)復(fù)雜度增加:需要管理多個(gè)數(shù)據(jù)源和業(yè)務(wù)拆分

二、多數(shù)據(jù)源配置策略

2.1 基本原理

多數(shù)據(jù)源配置是實(shí)現(xiàn)垂直分片最直接的方式,通過(guò)在SpringBoot中配置多個(gè)DataSource并為不同的業(yè)務(wù)模塊指定不同的數(shù)據(jù)源,實(shí)現(xiàn)業(yè)務(wù)數(shù)據(jù)的物理隔離。

2.2 實(shí)現(xiàn)步驟

2.2.1 配置多個(gè)數(shù)據(jù)源

首先在application.yml中配置多個(gè)數(shù)據(jù)源:

spring:
  datasource:
    # 用戶服務(wù)數(shù)據(jù)源
    user:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://user-db:3306/user_db
      username: user_app
      password: password
      
    # 訂單服務(wù)數(shù)據(jù)源
    order:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://order-db:3306/order_db
      username: order_app
      password: password
      
    # 產(chǎn)品服務(wù)數(shù)據(jù)源
    product:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://product-db:3306/product_db
      username: product_app
      password: password

2.2.2 創(chuàng)建數(shù)據(jù)源配置類

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.order")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.product")
    public DataSource productDataSource() {
        return DataSourceBuilder.create().build();
    }
}

2.2.3 為不同模塊配置獨(dú)立的事務(wù)管理器和JdbcTemplate

@Configuration
public class UserDbConfig {
    
    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;
    
    @Bean
    public JdbcTemplate userJdbcTemplate() {
        return new JdbcTemplate(userDataSource);
    }
    
    @Bean
    public PlatformTransactionManager userTransactionManager() {
        return new DataSourceTransactionManager(userDataSource);
    }
}

@Configuration
public class OrderDbConfig {
    
    @Autowired
    @Qualifier("orderDataSource")
    private DataSource orderDataSource;
    
    @Bean
    public JdbcTemplate orderJdbcTemplate() {
        return new JdbcTemplate(orderDataSource);
    }
    
    @Bean
    public PlatformTransactionManager orderTransactionManager() {
        return new DataSourceTransactionManager(orderDataSource);
    }
}

@Configuration
public class ProductDbConfig {
    
    @Autowired
    @Qualifier("productDataSource")
    private DataSource productDataSource;
    
    @Bean
    public JdbcTemplate productJdbcTemplate() {
        return new JdbcTemplate(productDataSource);
    }
    
    @Bean
    public PlatformTransactionManager productTransactionManager() {
        return new DataSourceTransactionManager(productDataSource);
    }
}

2.2.4 在Service層使用不同的數(shù)據(jù)源

@Service
public class UserService {
    
    @Autowired
    @Qualifier("userJdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    
    @Transactional("userTransactionManager")
    public User createUser(User user) {
        // 用戶數(shù)據(jù)庫(kù)操作
        // ...
    }
}

@Service
public class OrderService {
    
    @Autowired
    @Qualifier("orderJdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    
    @Transactional("orderTransactionManager")
    public Order createOrder(Order order) {
        // 訂單數(shù)據(jù)庫(kù)操作
        // ...
    }
}

2.3 優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn):

  • 配置簡(jiǎn)單直觀,容易理解
  • 與Spring生態(tài)高度集成
  • 對(duì)業(yè)務(wù)代碼侵入性低
  • 可以針對(duì)不同數(shù)據(jù)源配置不同的連接池參數(shù)

缺點(diǎn):

  • 無(wú)法動(dòng)態(tài)增減數(shù)據(jù)源
  • 分布式事務(wù)處理復(fù)雜
  • 適合業(yè)務(wù)模塊劃分明確且相對(duì)獨(dú)立的場(chǎng)景
  • 代碼中需要顯式指定使用哪個(gè)數(shù)據(jù)源和事務(wù)管理器

2.4 適用場(chǎng)景

  • 系統(tǒng)初期垂直分片設(shè)計(jì)
  • 業(yè)務(wù)模塊劃分明確,跨模塊調(diào)用較少的系統(tǒng)
  • 數(shù)據(jù)源數(shù)量較少且相對(duì)固定的場(chǎng)景

三、動(dòng)態(tài)數(shù)據(jù)源路由策略

3.1 基本原理

動(dòng)態(tài)數(shù)據(jù)源路由利用Spring提供的AbstractRoutingDataSource類,根據(jù)當(dāng)前執(zhí)行的上下文(如當(dāng)前線程)動(dòng)態(tài)決定使用哪個(gè)數(shù)據(jù)源。

這種方式實(shí)現(xiàn)了數(shù)據(jù)源選擇的透明化,使業(yè)務(wù)代碼無(wú)需關(guān)心具體使用哪個(gè)數(shù)據(jù)源。

3.2 實(shí)現(xiàn)步驟

3.2.1 創(chuàng)建數(shù)據(jù)源路由上下文

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

3.2.2 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源路由

public class DynamicDataSource extends AbstractRoutingDataSource {
    
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

3.2.3 配置動(dòng)態(tài)數(shù)據(jù)源

@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.order")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.product")
    public DataSource productDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        
        Map<Object, Object> dataSourceMap = new HashMap<>(3);
        dataSourceMap.put("user", userDataSource());
        dataSourceMap.put("order", orderDataSource());
        dataSourceMap.put("product", productDataSource());
        
        // 設(shè)置數(shù)據(jù)源映射
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        // 設(shè)置默認(rèn)數(shù)據(jù)源
        dynamicDataSource.setDefaultTargetDataSource(userDataSource());
        
        return dynamicDataSource;
    }
    
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

3.2.4 創(chuàng)建數(shù)據(jù)源切換注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceSelector {
    String value();
}

3.2.5 實(shí)現(xiàn)數(shù)據(jù)源切換的AOP切面

@Aspect
@Component
public class DataSourceAspect {
    
    @Pointcut("@annotation(com.example.config.DataSourceSelector)")
    public void dataSourcePointcut() {}
    
    @Before("dataSourcePointcut() && @annotation(dataSource)")
    public void switchDataSource(JoinPoint point, DataSourceSelector dataSource) {
        String dataSourceName = dataSource.value();
        DataSourceContextHolder.setDataSourceType(dataSourceName);
    }
    
    @After("dataSourcePointcut()")
    public void restoreDataSource(JoinPoint point) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

3.2.6 在Service層使用注解切換數(shù)據(jù)源

@Service
public class UserService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @DataSourceSelector("user")
    @Transactional
    public User createUser(User user) {
        // 用戶數(shù)據(jù)庫(kù)操作
        // ...
    }
}

@Service
public class OrderService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @DataSourceSelector("order")
    @Transactional
    public Order createOrder(Order order) {
        // 訂單數(shù)據(jù)庫(kù)操作
        // ...
    }
}

3.3 優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn):

  • 數(shù)據(jù)源切換對(duì)業(yè)務(wù)代碼透明,只需添加注解即可
  • 支持動(dòng)態(tài)增減數(shù)據(jù)源
  • 可以在運(yùn)行時(shí)根據(jù)不同條件切換數(shù)據(jù)源
  • 只需配置一個(gè)事務(wù)管理器,簡(jiǎn)化事務(wù)配置

缺點(diǎn):

  • 實(shí)現(xiàn)相對(duì)復(fù)雜
  • 依賴ThreadLocal,在異步或多線程環(huán)境下需要特別處理
  • 事務(wù)管理需要注意,避免切換數(shù)據(jù)源導(dǎo)致事務(wù)問(wèn)題
  • 不易實(shí)現(xiàn)分布式事務(wù)

3.4 適用場(chǎng)景

  • 業(yè)務(wù)模塊獨(dú)立性不強(qiáng),存在跨模塊訪問(wèn)需求的系統(tǒng)
  • 需要在運(yùn)行時(shí)動(dòng)態(tài)決定數(shù)據(jù)源的場(chǎng)景
  • 數(shù)據(jù)源數(shù)量可能動(dòng)態(tài)變化的系統(tǒng)

四、ORM框架多數(shù)據(jù)源配置策略

4.1 基本原理

利用ORM框架(如JPA、MyBatis)的多數(shù)據(jù)源支持,為不同的業(yè)務(wù)模塊配置獨(dú)立的ORM組件,實(shí)現(xiàn)對(duì)不同數(shù)據(jù)庫(kù)的透明訪問(wèn)。

這種方式結(jié)合了ORM的便利性和垂直分片的優(yōu)勢(shì)。

4.2 實(shí)現(xiàn)步驟(以JPA為例)

4.2.1 配置多個(gè)數(shù)據(jù)源

spring:
  # 用戶服務(wù)數(shù)據(jù)源
  datasource:
    user:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://user-db:3306/user_db
      username: user_app
      password: password
      
    # 訂單服務(wù)數(shù)據(jù)源
    order:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://order-db:3306/order_db
      username: order_app
      password: password
      
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect

4.2.2 配置用戶模塊的JPA配置

@Configuration
@EnableJpaRepositories(
    basePackages = "com.example.user.repository",
    entityManagerFactoryRef = "userEntityManagerFactory",
    transactionManagerRef = "userTransactionManager"
)
public class UserJpaConfig {
    
    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;
    
    @Bean
    public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
            .dataSource(userDataSource)
            .packages("com.example.user.entity")
            .persistenceUnit("userPU")
            .properties(getJpaProperties())
            .build();
    }
    
    @Bean
    public PlatformTransactionManager userTransactionManager(
            @Qualifier("userEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
    
    private Map<String, Object> getJpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        props.put("hibernate.hbm2ddl.auto", "update");
        return props;
    }
}

4.2.3 配置訂單模塊的JPA配置

@Configuration
@EnableJpaRepositories(
    basePackages = "com.example.order.repository",
    entityManagerFactoryRef = "orderEntityManagerFactory",
    transactionManagerRef = "orderTransactionManager"
)
public class OrderJpaConfig {
    
    @Autowired
    @Qualifier("orderDataSource")
    private DataSource orderDataSource;
    
    @Bean
    public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
            .dataSource(orderDataSource)
            .packages("com.example.order.entity")
            .persistenceUnit("orderPU")
            .properties(getJpaProperties())
            .build();
    }
    
    @Bean
    public PlatformTransactionManager orderTransactionManager(
            @Qualifier("orderEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
    
    private Map<String, Object> getJpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        props.put("hibernate.hbm2ddl.auto", "update");
        return props;
    }
}

4.2.4 創(chuàng)建實(shí)體類和Repository

用戶模塊:

// 實(shí)體類
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;
    // getters and setters
}

// Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByEmail(String email);
}

訂單模塊:

// 實(shí)體類
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private BigDecimal amount;
    private Date orderDate;
    // getters and setters
}

// Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByUserId(Long userId);
}

4.2.5 在Service層使用

@Service
@Transactional("userTransactionManager")
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

@Service
@Transactional("orderTransactionManager")
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private UserService userService;
    
    public Order createOrder(Order order) {
        // 驗(yàn)證用戶是否存在
        User user = userService.getUserById(order.getUserId());
        if (user == null) {
            throw new RuntimeException("User not found");
        }
        return orderRepository.save(order);
    }
    
    public List<Order> getUserOrders(Long userId) {
        return orderRepository.findByUserId(userId);
    }
}

4.3 優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn):

  • 充分利用ORM框架的便利性
  • 實(shí)體類和數(shù)據(jù)庫(kù)操作代碼保持簡(jiǎn)潔
  • 業(yè)務(wù)代碼不需要關(guān)心數(shù)據(jù)源切換
  • 對(duì)于不同業(yè)務(wù)模塊有清晰的包結(jié)構(gòu)隔離

缺點(diǎn):

  • 配置較為復(fù)雜
  • 跨模塊查詢需要在Service層手動(dòng)處理
  • 不同模塊的事務(wù)無(wú)法統(tǒng)一管理,分布式事務(wù)支持有限
  • 過(guò)多的EntityManagerFactory會(huì)增加內(nèi)存開銷

4.4 適用場(chǎng)景

  • 已經(jīng)使用ORM框架的項(xiàng)目
  • 業(yè)務(wù)模塊劃分明確,數(shù)據(jù)模型相對(duì)獨(dú)立
  • 開發(fā)團(tuán)隊(duì)熟悉JPA或其他ORM框架
  • 對(duì)分布式事務(wù)要求不高的場(chǎng)景

五、分庫(kù)中間件策略

5.1 基本原理

利用專業(yè)的分庫(kù)分表中間件(如ShardingSphere、MyCat等)進(jìn)行垂直分片,通過(guò)中間件提供的路由和代理功能,實(shí)現(xiàn)對(duì)多個(gè)數(shù)據(jù)庫(kù)的統(tǒng)一管理和訪問(wèn)。

這種方式將分片邏輯從應(yīng)用層下沉到中間件層,簡(jiǎn)化了應(yīng)用開發(fā)。

5.2 實(shí)現(xiàn)步驟(以ShardingSphere-JDBC為例)

5.2.1 添加依賴

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.0</version>
</dependency>

5.2.2 配置垂直分片規(guī)則

spring:
  shardingsphere:
    datasource:
      names: user-db,order-db,product-db
      user-db:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://user-db:3306/user_db
        username: user_app
        password: password
      order-db:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://order-db:3306/order_db
        username: order_app
        password: password
      product-db:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://product-db:3306/product_db
        username: product_app
        password: password
    
    rules:
      sharding:
        tables:
          # 用戶表配置
          users:
            actual-data-nodes: user-db.users
          user_address:
            actual-data-nodes: user-db.user_address
          
          # 訂單表配置
          orders:
            actual-data-nodes: order-db.orders
          order_items:
            actual-data-nodes: order-db.order_items
          
          # 產(chǎn)品表配置
          products:
            actual-data-nodes: product-db.products
          product_categories:
            actual-data-nodes: product-db.product_categories
    
    props:
      sql-show: true

5.2.3 創(chuàng)建實(shí)體類和Repository

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;
    // getters and setters
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 查詢方法
}

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private BigDecimal amount;
    // getters and setters
}

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByUserId(Long userId);
}

5.2.4 配置數(shù)據(jù)庫(kù)訪問(wèn)

@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
@EnableTransactionManagement
public class JpaConfig {
    
    @Bean
    public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.example.entity");
        factory.setDataSource(dataSource);
        factory.afterPropertiesSet();
        
        return factory.getObject();
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }
}

5.2.5 在Service層使用

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

@Service
@Transactional
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    public Order createOrder(Order order) {
        return orderRepository.save(order);
    }
    
    public List<Order> getUserOrders(Long userId) {
        return orderRepository.findByUserId(userId);
    }
}

5.3 優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn):

  • 分片邏輯下沉到中間件,對(duì)應(yīng)用層透明
  • 統(tǒng)一的事務(wù)管理,部分中間件支持弱XA事務(wù)
  • 應(yīng)用代碼無(wú)需關(guān)心數(shù)據(jù)源切換
  • 支持復(fù)雜的分片規(guī)則和讀寫分離

缺點(diǎn):

  • 引入額外的中間件,增加系統(tǒng)復(fù)雜度
  • 對(duì)SQL有一定限制,部分復(fù)雜查詢可能不支持
  • 性能上會(huì)有一定的損耗
  • 學(xué)習(xí)成本較高

5.4 適用場(chǎng)景

  • 大型系統(tǒng),數(shù)據(jù)量大且需要復(fù)雜分片策略
  • 需要同時(shí)支持垂直分片和水平分片的場(chǎng)景
  • 對(duì)分布式事務(wù)有一定要求的系統(tǒng)

六、微服務(wù)架構(gòu)下的垂直分片策略

6.1 基本原理

在微服務(wù)架構(gòu)中,每個(gè)微服務(wù)擁有自己獨(dú)立的數(shù)據(jù)庫(kù),通過(guò)業(yè)務(wù)功能的拆分自然實(shí)現(xiàn)了垂直分片。

不同微服務(wù)之間通過(guò)API調(diào)用而非直接數(shù)據(jù)庫(kù)訪問(wèn)進(jìn)行交互,實(shí)現(xiàn)了數(shù)據(jù)的物理隔離和訪問(wèn)控制。

6.2 實(shí)現(xiàn)步驟

6.2.1 拆分微服務(wù)和數(shù)據(jù)庫(kù)

根據(jù)業(yè)務(wù)領(lǐng)域劃分微服務(wù):

  • 用戶服務(wù):管理用戶相關(guān)數(shù)據(jù)
  • 訂單服務(wù):管理訂單相關(guān)數(shù)據(jù)
  • 產(chǎn)品服務(wù):管理產(chǎn)品相關(guān)數(shù)據(jù)
  • ...

每個(gè)微服務(wù)擁有獨(dú)立的數(shù)據(jù)庫(kù)。

6.2.2 用戶服務(wù)實(shí)現(xiàn)

// 用戶服務(wù)數(shù)據(jù)庫(kù)配置
@Configuration
@EnableJpaRepositories(basePackages = "com.example.userservice.repository")
public class UserServiceDbConfig {
    // 數(shù)據(jù)源、事務(wù)管理器等配置
}

// 用戶實(shí)體類
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;
    // getters and setters
}

// 用戶Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 查詢方法
}

// 用戶服務(wù)接口
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        return ResponseEntity.ok(userService.createUser(user));
    }
}

6.2.3 訂單服務(wù)實(shí)現(xiàn)

// 訂單服務(wù)數(shù)據(jù)庫(kù)配置
@Configuration
@EnableJpaRepositories(basePackages = "com.example.orderservice.repository")
public class OrderServiceDbConfig {
    // 數(shù)據(jù)源、事務(wù)管理器等配置
}

// 訂單實(shí)體類
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private BigDecimal amount;
    // getters and setters
}

// 訂單Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByUserId(Long userId);
}

// 用戶客戶端(Feign)
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
    
    @GetMapping("/api/users/{id}")
    User getUserById(@PathVariable Long id);
}

// 訂單服務(wù)
@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private UserClient userClient;
    
    public Order createOrder(Order order) {
        // 通過(guò)Feign調(diào)用用戶服務(wù)驗(yàn)證用戶
        User user = userClient.getUserById(order.getUserId());
        if (user == null) {
            throw new RuntimeException("User not found");
        }
        return orderRepository.save(order);
    }
}

// 訂單API
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody Order order) {
        return ResponseEntity.ok(orderService.createOrder(order));
    }
    
    @GetMapping("/user/{userId}")
    public ResponseEntity<List<Order>> getUserOrders(@PathVariable Long userId) {
        return ResponseEntity.ok(orderService.getUserOrders(userId));
    }
}

6.3 優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn):

  • 業(yè)務(wù)和數(shù)據(jù)完全解耦,每個(gè)服務(wù)獨(dú)立發(fā)展
  • 技術(shù)??梢造`活選擇,不同服務(wù)可以使用不同的數(shù)據(jù)庫(kù)類型
  • 服務(wù)獨(dú)立部署和擴(kuò)展,提高系統(tǒng)彈性 
  • 服務(wù)邊界清晰,符合領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)理念

缺點(diǎn):

  • 分布式事務(wù)處理復(fù)雜,通常需要采用最終一致性方案
  • 跨服務(wù)查詢需要通過(guò)API組合數(shù)據(jù),可能影響性能
  • 系統(tǒng)復(fù)雜度增加,運(yùn)維成本提高
  • 服務(wù)拆分需要充分考慮業(yè)務(wù)邊界,拆分不當(dāng)會(huì)導(dǎo)致頻繁的跨服務(wù)調(diào)用

6.4 適用場(chǎng)景

  • 大型復(fù)雜系統(tǒng),需要獨(dú)立擴(kuò)展不同業(yè)務(wù)模塊
  • 團(tuán)隊(duì)組織結(jié)構(gòu)與業(yè)務(wù)劃分一致,適合采用微服務(wù)架構(gòu)
  • 長(zhǎng)期演進(jìn)的系統(tǒng),需要技術(shù)棧靈活性
  • 對(duì)服務(wù)隔離性和彈性有較高要求的場(chǎng)景

七、策略比較

策略復(fù)雜度透明度事務(wù)支持跨庫(kù)查詢性能影響維護(hù)成本
多數(shù)據(jù)源配置單庫(kù)事務(wù)需代碼處理
動(dòng)態(tài)數(shù)據(jù)源路由單庫(kù)事務(wù)需代碼處理
ORM多數(shù)據(jù)源單庫(kù)事務(wù)需代碼處理
分庫(kù)中間件分布式事務(wù)部分支持
微服務(wù)架構(gòu)最終一致性API組合

注:分布式事務(wù)支持程度取決于所選中間件或自主實(shí)現(xiàn)的數(shù)據(jù)一致性保障機(jī)制

八、垂直分片的最佳實(shí)踐

8.1 數(shù)據(jù)模型設(shè)計(jì)

按業(yè)務(wù)領(lǐng)域劃分表

將相關(guān)性強(qiáng)的表分到同一個(gè)數(shù)據(jù)庫(kù)

盡量避免跨庫(kù)關(guān)聯(lián)查詢

使用冗余字段減少跨庫(kù)依賴

合理使用主鍵

避免使用自增主鍵(特別是在未來(lái)可能需要水平分片的場(chǎng)景)

考慮使用UUID或分布式ID生成器

建立合理的索引降低查詢壓力

數(shù)據(jù)冗余與一致性平衡

適當(dāng)冗余關(guān)鍵數(shù)據(jù)降低跨庫(kù)查詢

建立數(shù)據(jù)同步機(jī)制保證最終一致性

區(qū)分強(qiáng)一致性場(chǎng)景和最終一致性場(chǎng)景

8.2 事務(wù)處理

本地事務(wù)處理

盡量將事務(wù)限制在單一數(shù)據(jù)庫(kù)內(nèi)

單數(shù)據(jù)庫(kù)事務(wù)使用Spring的@Transactional注解

分布式事務(wù)策略

對(duì)于簡(jiǎn)單場(chǎng)景:兩階段提交(XA)

對(duì)于高并發(fā)場(chǎng)景:TCC(Try-Confirm-Cancel)

對(duì)于長(zhǎng)事務(wù)場(chǎng)景:Saga模式

考慮使用Seata等分布式事務(wù)框架

最終一致性實(shí)現(xiàn)

基于消息隊(duì)列的事件驅(qū)動(dòng)架構(gòu)

補(bǔ)償機(jī)制和重試策略

冪等設(shè)計(jì)確保操作可重復(fù)執(zhí)行

8.3 查詢優(yōu)化

減少跨庫(kù)查詢

合理劃分業(yè)務(wù)邊界,減少跨業(yè)務(wù)查詢需求

使用數(shù)據(jù)冗余避免頻繁跨庫(kù)查詢

考慮使用CQRS模式,為查詢場(chǎng)景構(gòu)建專用視圖

查詢路由策略

分析查詢模式,優(yōu)化分片鍵選擇

對(duì)于復(fù)雜查詢,考慮使用查詢視圖或搜索引擎

合理使用緩存減少數(shù)據(jù)庫(kù)訪問(wèn)

結(jié)果聚合處理

在應(yīng)用層對(duì)多數(shù)據(jù)源結(jié)果進(jìn)行聚合

使用并行查詢提高效率

結(jié)果分頁(yè)和懶加載減少數(shù)據(jù)傳輸量

以上就是SpringBoot實(shí)現(xiàn)垂直分片的六種策略的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot垂直分片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring中事務(wù)管理的四種方法(銀行轉(zhuǎn)賬為例)

    Spring中事務(wù)管理的四種方法(銀行轉(zhuǎn)賬為例)

    這篇文章主要給大家介紹了關(guān)于Spring中事務(wù)管理的四種方法,文中是以銀行轉(zhuǎn)賬為例,通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • servlet生命周期_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    servlet生命周期_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了servlet生命周期的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Java SpringMVC異常處理機(jī)制詳解

    Java SpringMVC異常處理機(jī)制詳解

    這篇文章主要介紹了springmvc如何進(jìn)行異常處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-09-09
  • struts2靜態(tài)資源映射代碼示例

    struts2靜態(tài)資源映射代碼示例

    這篇文章主要介紹了struts2靜態(tài)資源映射的相關(guān)內(nèi)容,涉及了具體代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09
  • Mybatis模糊查詢和動(dòng)態(tài)sql語(yǔ)句的用法

    Mybatis模糊查詢和動(dòng)態(tài)sql語(yǔ)句的用法

    今天小編就為大家分享一篇關(guān)于Mybatis模糊查詢和動(dòng)態(tài)sql語(yǔ)句的用法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • Java使用Deque實(shí)現(xiàn)堆棧的方法

    Java使用Deque實(shí)現(xiàn)堆棧的方法

    這篇文章主要介紹了Java使用Deque實(shí)現(xiàn)堆棧的方法,實(shí)例分析了java簡(jiǎn)單實(shí)現(xiàn)堆棧的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • 基于java中子類的繼承性的應(yīng)用介紹

    基于java中子類的繼承性的應(yīng)用介紹

    本篇介紹了,基于java中子類的繼承性的應(yīng)用。需要的朋友參考下
    2013-05-05
  • Java中Spring獲取bean方法小結(jié)

    Java中Spring獲取bean方法小結(jié)

    Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架,如何在程序中獲取Spring配置的bean呢?下面通過(guò)本文給大家介紹Java中Spring獲取bean方法小結(jié),對(duì)spring獲取bean方法相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2016-01-01
  • 關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType對(duì)Filter配置的影響

    關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType

    這篇文章主要介紹了關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType對(duì)Filter配置的影響,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Springcloud Nacos基本操作代碼實(shí)例

    Springcloud Nacos基本操作代碼實(shí)例

    這篇文章主要介紹了Springcloud Nacos基本操作代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論

洛隆县| 绥棱县| 西峡县| 买车| 湘乡市| 安溪县| 阜康市| 涪陵区| 上林县| 金溪县| 湟源县| 东阳市| 饶平县| 荃湾区| 扶绥县| 青浦区| 社旗县| 瓮安县| 吕梁市| 汝南县| 四会市| 腾冲县| 伊通| 赤壁市| 哈巴河县| 广东省| 勐海县| 临沧市| 墨脱县| 班戈县| 黄平县| 万源市| 永德县| 渝北区| 巫溪县| 扶绥县| 乌兰县| 彝良县| 剑河县| 长顺县| 云安县|