【1.5 漫画TiDB分布式数据库】

发布于:2025-07-06 ⋅ 阅读:(15) ⋅ 点赞:(0)

🌟 漫画TiDB分布式数据库

👨‍💻 小明:“老王,TiDB作为NewSQL数据库,它是如何既保证ACID又实现水平扩展的?”

🧙‍♂️ 架构师老王:“TiDB是PingCAP开发的分布式关系数据库,它将传统数据库的ACID特性与NoSQL的扩展性完美结合!让我们深入了解这个’钛’级数据库!”

📚 目录


🏗️ TiDB核心架构

🔧 三层架构设计

┌─────────────────────────────────────────┐
│                TiDB架构                 │
├─────────────────────────────────────────┤
│  TiDB Server (SQL Layer)               │
│  ├── Parser (SQL解析器)                 │
│  ├── Optimizer (查询优化器)             │
│  ├── Executor (执行引擎)                │
│  └── Session Management                 │
├─────────────────────────────────────────┤
│  TiKV Cluster (Storage Layer)          │
│  ├── Raft Consensus (一致性协议)        │
│  ├── RocksDB (存储引擎)                 │
│  ├── Coprocessor (协处理器)             │
│  └── Region Management                  │
├─────────────────────────────────────────┤
│  PD Server (Placement Driver)          │
│  ├── Cluster Metadata                  │
│  ├── Region Scheduling                 │
│  ├── Load Balancing                    │
│  └── TSO (时间戳Oracle)                │
└─────────────────────────────────────────┘

💾 Java连接配置

@Configuration
public class TiDBConfiguration {
   
    
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.tidb")
    public DataSource tidbDataSource() {
   
        HikariConfig config = new HikariConfig();
        
        // TiDB连接URL
        config.setJdbcUrl("jdbc:mysql://tidb-server:4000/testdb?" +
                         "useUnicode=true&characterEncoding=utf8&" +
                         "useSSL=false&serverTimezone=Asia/Shanghai&" +
                         "rewriteBatchedStatements=true");
        config.setUsername("root");
        config.setPassword("");
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        
        // 连接池优化配置
        config.setMaximumPoolSize(50);
        config.setMinimumIdle(10);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(300000);
        config.setMaxLifetime(1800000);
        
        // TiDB特定优化
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        config.addDataSourceProperty("useLocalSessionState", "true");
        config.addDataSourceProperty("rewriteBatchedStatements", "true");
        
        return new HikariDataSource(config);
    }
    
    // 多数据源配置(TiDB + MySQL)
    @Bean
    public DataSource multiDataSource() {
   
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("tidb", tidbDataSource());
        targetDataSources.put("mysql", mysqlDataSource());
        
        RoutingDataSource routingDataSource = new RoutingDataSource();
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(tidbDataSource());
        
        return routingDataSource;
    }
}

⚡ 分布式事务原理

🔄 2PC分布式事务

// TiDB分布式事务管理器
@Service
public class TiDBTransactionService {
   
    
    @Autowired
    private DataSource tidbDataSource;
    
    // 分布式事务示例
    @Transactional(rollbackFor = Exception.class)
    public void distributedTransaction() {
   
        try (Connection conn = tidbDataSource.getConnection()) {
   
            // 设置事务隔离级别
            conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            conn.setAutoCommit(false);
            
            // 业务操作1:更新账户余额
            updateAccountBalance(conn, "account1", new BigDecimal("-100"));
            
            // 业务操作2:更新账户余额
            updateAccountBalance(conn, "account2", new BigDecimal("100"));
            
            // 业务操作3:记录转账日志
            insertTransferLog(conn, "account1", "account2", new BigDecimal("100"));
            
            conn.commit();
            log.info("分布式事务提交成功");
            
        } catch (SQLException e) {
   
            log.error("分布式事务执行失败", e);
            throw new TransactionException("事务回滚", e);
        }
    }
    
    private void updateAccountBalance(Connection conn, String accountId, BigDecimal amount) 
            throws SQLException {
   
        String sql = "UPDATE accounts SET balance = balance + ? WHERE account_id = ?";
        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
   
            stmt.setBigDecimal(1, amount);
            stmt.setString(2, accountId);
            
            int rows = stmt.executeUpdate();
            if (rows == 0) {
   
                throw new SQLException("账户不存在: " + accountId);
            }
        }
    }
}

// 乐观锁控制
@Entity
@Table(name = "products")
public class Product {
   
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name")
    private String name;
    
    @Column(name = "stock")
    private Integer stock;
    
    // TiDB支持的版本控制
    @Version
    @Column(name = "version")
    private Long version;
    
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
}

// 分布式锁实现
@Service
public class TiDBDistributedLockService {
   
    
    @PersistenceContext
    private EntityManager entityManager;
    
    // 使用TiDB的SELECT FOR UPDATE实现分布式锁
    public boolean tryLock(String lockKey, int timeoutSeconds) {
   
        try {
   
            String sql = """
                SELECT lock_key FROM distributed_locks 
                WHERE lock_key = :lockKey 
                FOR UPDATE NOWAIT
                """;
            
            Query query = entityManager.createNativeQuery(sql);
            query.setParameter("lockKey", lockKey);
            query.getSingleResult();
            
            return true;
        } catch (Exception e) {
   
            return false;
        }
    }
    
    // 悲观锁示例
    @Transactional
    public void processWithLock(Long productId) {
   
        // 使用悲观锁防止并发修改
        String sql = """
            SELECT * FROM products 
            WHERE id = :productId 
            FOR UPDATE
            "