开发者

SpringBoot实现垂直分片的六种策略

开发者 https://www.devze.com 2025-06-22 11:40 出处:网络 作者: 风象南
目录一、垂直分片概述1.1 什么是垂直分片1.2 垂直分片的优势1.3 垂直分片的挑战二、多数据源配置策略2.1 基本原理2.2 实现步骤2.2.1 配置多个数据源2.2.2 创建数据源配置类2.2.3 为不同模块配置独立的事务管理器和Jd
目录
  • 一、垂直分片概述
    • 1.1 什么是垂直分片
    • 1.2 垂直分片的优势
    • 1.3 垂直分片的挑战
  • 二、多数据源配置策略
    • 2.1 基本原理
    • 2.2 实现步骤
      • 2.2.1 配置多个数据源
      • 2.2.2 创建数据源配置类
      • 2.2.3 为不同模块配置独立的事务管理器和JdbcTemplate
      • 2.2.4 在Service层使用不同的数据源
    • 2.3 优缺点分析
      • 2.4 适用场景
      • 三、动态数据源路由策略
        • 3.1 基本原理
          • 3.2 实现步骤
            • 3.2.1 创建数据源路由上下文
            • 3.2.2 实现动态数据源路由
            • 3.2.3 配置动态数据源
            • 3.2.4 创建数据源切换注解
            • 3.2.5 实现数据源切换的AOP切面
            • 3.2.6 在Service层使用注解切换数据源
          • 3.3 优缺点分析
            • 3.4 适用场景
            • 四、ORM框架多数据源配置策略
              • 4.1 基本原理
                • 4.2 实现步骤(以JPA为例)
                  • 4.2.1 配置多个数据源
                  • 4.2.2 配置用户模块的JPA配置
                  • 4.2.3 配置订单模块的JPA配置
                  • 4.2.4 创建实体类和Repository
                  • 4.2.5 在Service层使用
                • 4.3 优缺点分析
                  • 4.4 适用场景
                  • 五、分库中间件策略
                    • 5.1 基本原理
                      • 5.2 实现步骤(以ShardingSphere-JDBC为例)
                        • 5.2.1 添加依赖
                        • 5.2.2 配置垂直分片规则
                        • 5.2.3 创建实体类和Repository
                        • 5.2.4 配置数据库访问
                        • 5.2.5 在Service层使用
                      • 5.3 优缺点分析
                        • 5.4 适用场景
                        • 六、微服务架构下的垂直分片策略
                          • 6.1 基本原理
                            • 6.2 实现步骤
                              • 6.2.1 拆分微服务和数据库
                              • 6.2.2 用户服务实现
                              • 6.2.3 订单服务实现
                            • 6.3 优缺点分析
                              • 6.4 适用场景
                              • 七、策略比较
                                • 八、垂直分片的最佳实践
                                  • 8.1 数据模型设计
                                    • 8.2 事务处理
                                      • 8.3 查询优化

                                      一、垂直分片概述

                                      1.1 什么是垂直分片

                                      垂直分片是数据库分库分表的一种方式,它按照业务功能或数据表将原本在同一个数据库的数据拆分到不同的数据库实例中。

                                      与水平分片(将同一张表的数据按照某种规则分散到不同库或表中)不同,垂直分片主要解决的是业务模块的解耦和单库的资源瓶颈问题。

                                      1.2 垂直分片的优势

                                      • 减轻单库压力:将不同业务模块分散到不同数据库,分散了数据库负载
                                      • 业务解耦:不同业务模块的数据独立存储,便于业务模块的独立扩展
                                      • 提高系统可用性:单个数据库故障只会影响部分业务模块
                                      • 便于维护和优化:可以针对不同业务特点选择不同的数据库类型和优化策略
                                      • 权限隔离:便于进行业务级别的数据访问权限控制

                                      1.3 垂直分片的挑战

                                      • 分布式事务:跨库操作时需要处理分布式事务
                                      • 数据一致性:多库数据同步和一致性保证
                                      • 跨库查询:涉及多个业务模块的查询变得复杂
                                      • 开发复杂度增加:需要管理多个数据源和业务拆分

                                      二、多数据源配置策略

                                      2.1 基本原理

                                      多数据源配置是实现垂直分片最直接的方式,通过在SpringBoot中配置多个DataSource并为不同的业务模块指定不同的数据源,实现业务数据的物理隔离。

                                      2.2 实现步骤

                                      2.2.1 配置多个数据源

                                      首先在application.yml中配置多个数据源:

                                      spring:
                                        datasource:
                                          # 用户服务数据源
                                          user:
                                            driver-class-name: com.mysql.cj.jdbc.Driver
                                            url: jdbc:mysql://user-db:3306/user_db
                                            username: user_app
                                            password: password
                                            
                                          # 订单服务数据源
                                          order:
                                            driver-class-name: com.mysql.cj.jdbc.Driver
                                            url: jdbc:mysql://order-db:3306/order_db
                                            username: order_app
                                            password: password
                                            
                                          # 产品服务数据源
                                          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 创建数据源配置类

                                      @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 为不同模块配置独立的事务管理器和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层使用不同的数据源

                                      @Service
                                      public class UserService {
                                          
                                          @Autowired
                                          @Qualifier("userJdbcTemplate")
                                          private JdbcTemplate jdbcTemplate;
                                          
                                          @Transactional("userTransactionManager")
                                          public User createUser(User user) {
                                              // 用户数据库操作
                                              // ...
                                          }
                                      }
                                      
                                      @Service
                                      public class OrderService {
                                          
                                          @Autowired
                                          @Qualifier("orderJdbcTemplate")
                                          private JdbcTemplate jdbcTemplate;
                                          
                                          @Transactional("orderTransactionManager")
                                          public Order createOrder(Order order) {
                                              // 订单数据库操作
                                              // ...
                                          }
                                      }
                                      

                                      2.3 优缺点分析

                                      优点:

                                      • 配置简单直观,容易理解
                                      • 与Spring生态高度集成
                                      • 对业务代码侵入性低
                                      • 可以针对不同数据源配置不同的连接池参数

                                      缺点:

                                      • 无法动态增减数据源
                                      • 分布式事务处理复杂
                                      • 适合业务模块划分明确且相对独立的场景
                                      • 代码中需要显式指定使用哪个数据源和事务管理器

                                      2.4 适用场景

                                      • 系统初期垂直分片设计
                                      • 业务模块划分明确,跨模块调用较少的系统
                                      • 数据源数量较少且相对固定的场景

                                      三、动态数据源路由策略

                                      3.1 基本原理

                                      动态数据源路由利用Spring提供的AbstractRoutingDataSource类,根据当前执行的上下文(如当前线程)动态决定使用哪个数据源。

                                      这种方式实现了数据源选择的透明化,使业务代码无需关心具体使用哪个数据源。

                                      3.2 实现步骤

                                      3.2.1 创建数据源路由上下文

                                      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 实现动态数据源路由

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

                                      3.2.3 配置动态数据源

                                      @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 orderD编程ataSource() {
                                              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());
                                              
                                              // 设置数据源映射
                                              dynamicDataSource.setTargetDataSources(dataSourceMap);
                                              // 设置默认数据源
                                              dynamicDataSource.setDefaultTargetDataSource(userDataSource());
                                              
                                              return dynamicDataSource;
                                          }
                                          
                                          @Bean
                                          public PlatformTransactionManager transactionManager() {
                                              return new DataSourceTransactionManager(dynamicDataSource());
                                          }
                                      }
                                      

                                      3.2.4 创建数据源切换注解

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

                                      3.2.5 实现数据源切换的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层使用注解切换数据源

                                      @Service
                                      public class UserService {
                                          
                                          @Autowired
                                          private JdbcTemplate jdbcTemplate;
                                          
                                          @DataSourceSelector("user")
                                          @Transactional
                                          public User createUser(User user) {
                                              // 用户数据库操作
                                              // ...
                                          }
                                      }
                                      
                                      @Service
                                      public class OrderService {
                                          
                                          @Autowired
                                          private JdbcTemplate jdbcTemplate;
                                          
                                          @DataSourceSelector("order")
                                          @Transactional
                                          public Order createOrder(Order order) {
                                              // 订单数据库操作
                                              // ...
                                          }
                                      }
                                      

                                      3.3 优缺点分析

                                      优点:

                                      • 数据源切换对业务代码透明,只需添加注解即可
                                      • 支持动态增减数据源
                                      • 可以在运行时根据不同条件切换数据源
                                      • 只需配置一个事务管理器,简化事务配置

                                      缺点:

                                      • 实现相对复杂
                                      • 依赖ThreadLocal,在异步或多线程环境下需要特别处理
                                      • 事务管理需要注意,避免切换数据源导致事务问题
                                      • 不易实现分布式事务

                                      3.4 适用场景

                                      • 业务模块独立性不强,存在跨模块访问需求的系统
                                      • 需要在运行时动态决定数据源的场景
                                      • 数据源数量可能动态变化的系统

                                      四、ORM框架多数据源配置策略

                                      4.1 基本原理

                                      利用ORM框架(如JPA、MyBATis)的多数据源支持,为不同的业务模块配置独立的ORM组件,实现对不同数据库的透明访问。

                                      这种方式结合了ORM的便利性和垂直分片的优势。

                                      4.2 实现步骤(以JPA为例)

                                      4.2.1 配置多个数据源

                                      spring:
                                        # 用户服务数据源
                                        datasource:
                                          user:
                                            driver-class-name: com.mysql.cj.jdbc.Driver
                                            url: jdbc:mysql://user-db:3306/user_db
                                            username: user_app
                                            password: password
                                            
                                          # 订单服务数据源
                                          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 创建实体类和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
                                      @Repository
                                      public interface UserRepository extends JpaRepository<User, Long> {
                                          List<User> findByEmail(String email);
                                      }
                                      

                                      订单模块:

                                      // 实体类
                                      @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) {
                                              // 验证用户是否存在
                                              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 优缺点分析

                                      优点:

                                      • 充分利用ORM框架的便利性
                                      • 实体类和数据库操作代码保持简洁
                                      • 业务代码不需要关心数据源切换
                                      • 对于不同业务模块有清晰的包结构隔离

                                      缺点:

                                      • 配置较为复杂
                                      • 跨模块查询需要在Service层手动处理
                                      • 不同模块的事务无法统一管理,分布式事务支持有限
                                      • 过多的EntityManagerFactory会增加内存开销

                                      4.4 适用场景

                                      • 已经使用ORM框架的项目
                                      • 业务模块划分明确,数据模型相对独立
                                      • 开发团队熟悉JPA或其他ORM框架
                                      • 对分布式事务要求不高的场景

                                      五、分库中间件策略

                                      5.1 基本原理

                                      利用专业的分库分表中间件(如ShardingSphere、MyCat等)进行垂直分片,通过中间件提供的路由和代理功能,实现对多个数据库的统一管理和访问。

                                      这种方式将分片逻辑从应用层下沉到中间件层,简化了应用开发。

                                      5.2 实现步骤(以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 配置垂直分片规则

                                      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
                                                
                                                # 产品表配置
                                                products:
                                                  actual-data-nodes: product-db.products
                                                product_categories:
                                                  actual-data-nodes: product-db.product_categories
                                          
                                          props:
                                            sql-show: true
                                      

                                      5.2.3 创建实体类和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 配置数据库访问

                                      @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(www.devze.comUser 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(orde编程r);
                                          }
                                          
                                          public List<Order> getUserOrders(Long userId) {
                                              return orderRepository.findByUserId(userId);
                                          }
                                      }
                                      

                                      5.3 优缺点分析

                                      优点:

                                      • 分片逻辑下沉到中间件,对应用层透明
                                      • 统一的事务管理,部分中间件支持弱XA事务
                                      • 应用代码无需关心数据源切换
                                      • 支持复杂的分片规则和读写分离

                                      缺点:

                                      • 引入额外的中间件,增加系统复杂度
                                      • 对SQL有一定限制,部分复杂查询可能不支持
                                      • 性能上会有一定的损耗
                                      • 学习成本较高

                                      5.4 适用场景

                                      • 大型系统,数据量大且需要复杂分片策略
                                      • 需要同时支持垂直分片和水平分片的场景
                                      • 对分布式事务有一定要求的系统

                                      六、微服务架构下的垂直分片策略

                                      6.1 基本原理

                                      在微服务架构中,每个微服务拥有自己独立的数据库,通过业务功能的拆分自然实现了垂直分片。

                                      不同微服务之间通过API调用而非直接数据库访问进行交互,实现了数据的物理隔离和访问控制。

                                      6.2 实现步骤

                                      6.2.1 拆分微服务和数据库

                                      根据业务领域划分微服务:

                                      • 用户服务:管理用户相关数据
                                      • 订单服务:管理订单相关数据
                                      • 产品服务:管理产品相关数据
                                      • ...

                                      每个微服务拥有独立的数据库。

                                      6.2.2 用户服务实现

                                      // 用户服务数据库配置
                                      @Configuration
                                      @EnableJpaRepositories(basePackages = "com.example.userservice.repository")
                                      public class UserServiceDbConfig {
                                          // 数据源、事务管理器等配置
                                      }
                                      
                                      // 用户实体类
                                      @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> {
                                          // 查询方法
                                      }
                                      
                                      // 用户服务接口
                                      @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 订单服务实现

                                      // 订单服务数据库配置
                                      @Configuration
                                      @EnableJpaRepositories(basePackages = "com.example.orderservice.repository")
                                      public class OrderServiceDbConfig {
                                          // 数据源、事务管理器等配置
                                      }
                                      
                                      // 订单实体类
                                      @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);
                                      }
                                      
                                      // 订单服务
                                      @Service
                                      public class OrderService {
                                          
                                          @Autowired
                                          private OrderRepository orderRepository;
                                          
                                          @Autowired
                                          private UserClient userClient;
                                          
                                          public Order createOrder(Order order) {
                                              // 通过Feign调用用户服务验证用户
                                              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 优缺点分析

                                      优点:

                                      • 业务和数据完全解耦,每个服务独立发展
                                      • 技术栈可以灵活选择,不同服务可以使用不同的数据库类型
                                      • 服务独立部署和扩展,提高系统弹性 
                                      • 服务边界清晰,符合领域驱动设计理念

                                      缺点:

                                      • 分布式事务处理复杂,通常需要采用最终一致性方案
                                      • 跨服务查询需要通过API组合数据,可能影响性能
                                      • 系统复杂度增加,运维成本提高
                                      • 服务拆分需要充分考虑业务边界,拆分不当会导致频繁的跨服务调用

                                      6.4 适用场景

                                      • 大型复杂系统,需要独立扩展不同业务模块
                                      • 团队组织结构与业务划分一致,适合采用微服务架构
                                      • 长期演进的系统,需要技术栈灵活性
                                      • 对服务隔离性和弹性有较高要求的场景

                                      七、策略比较

                                      策略复杂度透明度事务支持跨库查询性能影响维护成本
                                      多数据源配置单库事务需代码处理
                                      动态数据源路由单库事务需代码处理
                                      ORM多数据源单库事务需代码处理
                                      分库中间件分布式事务部分支持
                                      微服务架构最终一致性API组合

                                      注:分布式事务支持程度取决于所选中间件或自主实现的数据一致性保障机制

                                      八、垂直分片的最佳实践

                                      8.1 数据模型设计

                                      按业务领域划分表

                                      将相关性强的表分到同一个数据库

                                      尽量避免跨库关联查询

                                      使用冗余字段减少跨库依赖

                                      合理使用主键

                                      避免使用自增主键(特别是在未来可能需要水平分片的场景)

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

                                      建立合理的索引降低查询压力

                                      数据冗余与一致性平衡

                                      适当冗余关键数据降低跨库查询

                                      建立数据同步机制保证最终一致性

                                      区分强一致性场景和最终一致性场景

                                      8.2 事务处理

                                      本地事务处理

                                      尽量将事务限制在单一数据库内

                                      单数据库事务使用Spring的@Transactional注解

                                      分布式事务策略

                                      对于简单场景:两阶段提交(XA)

                                      对于高并发场景:TCC(Try-Confirm-Cancel)

                                      对于长事务场景:Saga模式

                                      考虑使用Seata等分布式事务框架

                                      最终一致性实现

                                      基于消息队列的事件驱动架构

                                      补偿机制和重试策略

                                      幂等设计确保操作可重复执行

                                      8.3 查询优化

                                      减少跨库查询

                                      合理划分业务边界,减少跨业务查询需求

                                      使用数据冗余避免频繁跨库查询

                                      考虑使用CQRS模式,为查询场景构建专用视图

                                      查询路由策略

                                      分析查询模式,优化分片键选择

                                      对于复杂查询,考虑使用查询视图或搜索引擎

                                      合理使用缓存减少数据库访问

                                      结果聚合处理

                                      在应用层对多数据源结果进行聚合

                                      使用并行查询提高效率

                                      结果分页和懒加载减少数据传输量

                                      以上就是SpringBoot实现垂直分片的六种策略的详细内容,更多关于SpringBoot垂直分片的资料请关注编程客栈(www.devze.com)其它相关文章!

                                      0

                                      精彩评论

                                      暂无评论...
                                      验证码 换一张
                                      取 消

                                      关注公众号