🌟 漫画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
"