轻量级事务 #

一、LWT概述 #

1.1 什么是LWT #

轻量级事务(Lightweight Transactions, LWT)基于Paxos协议,提供条件更新能力。

text
LWT特点:

✓ 条件插入/更新
✓ 原子性保证
✓ 线性一致性
✓ 基于Paxos协议

1.2 LWT vs 普通操作 #

特性 LWT 普通操作
条件检查
原子性 最终一致
性能 低(4次往返)
适用场景 需要条件判断 一般操作

二、IF NOT EXISTS #

2.1 条件插入 #

sql
-- 仅当记录不存在时插入
INSERT INTO users (user_id, email, name)
VALUES (uuid(), 'unique@example.com', '张三')
IF NOT EXISTS;

-- 返回结果
-- [applied] | user_id | email              | name
------------+---------+--------------------+-------
--      True | uuid    | unique@example.com | 张三

-- 如果记录已存在
-- [applied] | user_id | email              | name
------------+---------+--------------------+-------
--     False | uuid    | existing@ex.com    | 李四

2.2 应用场景 #

sql
-- 唯一邮箱注册
INSERT INTO users (user_id, email, name)
VALUES (uuid(), ?, ?)
IF NOT EXISTS;

-- 唯一用户名
INSERT INTO user_names (username, user_id)
VALUES (?, ?)
IF NOT EXISTS;

-- 初始化计数器
INSERT INTO counters (counter_id, value)
VALUES (?, 0)
IF NOT EXISTS;

三、IF条件更新 #

3.1 基本条件更新 #

sql
-- 条件更新
UPDATE users 
SET email = 'new@example.com'
WHERE user_id = ?
IF email = 'old@example.com';

-- 多条件更新
UPDATE orders 
SET status = 'shipped'
WHERE order_id = ?
IF status = 'pending' AND amount > 0;

3.2 条件删除 #

sql
-- 条件删除
DELETE FROM orders 
WHERE order_id = ?
IF status = 'cancelled';

-- 条件删除列
DELETE email FROM users 
WHERE user_id = ?
IF email = 'old@example.com';

3.3 复杂条件 #

sql
-- 多列条件
UPDATE products 
SET stock = stock - 1
WHERE product_id = ?
IF stock > 0;

-- 组合条件
UPDATE accounts 
SET balance = balance - ?
WHERE account_id = ?
IF balance >= ? AND status = 'active';

四、BATCH中的LWT #

4.1 条件批量操作 #

sql
-- 条件批量操作
BEGIN BATCH
    UPDATE users 
    SET email = 'new@example.com' 
    WHERE user_id = ?
    IF email = 'old@example.com';
    
    INSERT INTO audit_log (log_id, action, timestamp)
    VALUES (uuid(), 'email_change', toTimestamp(now()));
APPLY BATCH;

4.2 多条件批量 #

sql
-- 多条件批量
BEGIN BATCH
    UPDATE accounts 
    SET balance = balance - 100 
    WHERE account_id = ?
    IF balance >= 100;
    
    UPDATE accounts 
    SET balance = balance + 100 
    WHERE account_id = ?
    IF balance >= 0;
    
    INSERT INTO transactions (tx_id, from_account, to_account, amount)
    VALUES (uuid(), ?, ?, 100);
APPLY BATCH;

五、性能影响 #

5.1 性能开销 #

text
LWT性能开销:

网络往返
├── 4次往返(Paxos协议)
├── Prepare → Propose → Commit → Read
└── 延迟显著增加

吞吐量
├── 比普通操作低很多
├── 单节点约1000 TPS
└── 受网络延迟影响

建议
├── 仅在必要时使用
├── 避免频繁使用
└── 考虑替代方案

5.2 性能对比 #

text
性能对比(大致):

普通操作
├── 延迟:1-5ms
├── 吞吐:高
└── 适合:大部分场景

LWT操作
├── 延迟:10-50ms
├── 吞吐:低
└── 适合:需要条件判断的场景

六、最佳实践 #

6.1 使用场景 #

text
LWT适用场景:

适合
├── 唯一性保证
├── 状态转换
├── 乐观锁
└── 条件更新

不适合
├── 高频操作
├── 大批量操作
├── 对性能敏感
└── 可容忍短暂不一致

6.2 替代方案 #

sql
-- 替代方案1:应用层检查
-- 先查询,再插入/更新
SELECT email FROM users WHERE user_id = ?;
-- 应用层判断
INSERT INTO users ...

-- 替代方案2:唯一约束表
-- 使用单独的表存储唯一约束
INSERT INTO unique_emails (email, user_id)
VALUES (?, ?)
IF NOT EXISTS;

-- 替代方案3:时间戳版本
-- 使用时间戳作为版本号
UPDATE users 
SET email = ?, version = ?
WHERE user_id = ? AND version = old_version;

6.3 设计建议 #

text
设计建议:

1. 限制使用范围
   └── 仅在真正需要时使用

2. 减少条件复杂度
   └── 简单条件性能更好

3. 监控性能
   └── 关注延迟和吞吐

4. 考虑一致性级别
   └── SERIAL/LOCAL_SERIAL

5. 准备回滚方案
   └── 处理条件不满足的情况

七、一致性级别 #

7.1 SERIAL一致性 #

sql
-- SERIAL一致性(默认)
INSERT INTO users (user_id, email)
VALUES (?, ?)
IF NOT EXISTS
USING CONSISTENCY SERIAL;

-- LOCAL_SERIAL(多数据中心)
INSERT INTO users (user_id, email)
VALUES (?, ?)
IF NOT EXISTS
USING CONSISTENCY LOCAL_SERIAL;

7.2 一致性级别选择 #

text
一致性级别选择:

SERIAL
├── 全局线性一致
├── 跨数据中心
└── 延迟较高

LOCAL_SERIAL
├── 本地数据中心线性一致
├── 性能较好
└── 推荐多数据中心使用

八、常见问题 #

8.1 条件不满足 #

sql
-- 检查返回结果
UPDATE users 
SET email = 'new@example.com'
WHERE user_id = ?
IF email = 'old@example.com';

-- 处理
-- 如果 [applied] = False,条件不满足
-- 需要处理失败情况

8.2 性能问题 #

text
性能问题解决:

1. 减少LWT使用
   └── 重新设计数据模型

2. 使用LOCAL_SERIAL
   └── 多数据中心场景

3. 批量操作
   └── 合并多个LWT

4. 异步处理
   └── 非关键路径异步化

九、总结 #

轻量级事务要点:

  1. 条件操作:IF NOT EXISTS、IF条件
  2. Paxos协议:4次网络往返
  3. 性能开销:比普通操作低很多
  4. 适用场景:唯一性、状态转换、乐观锁
  5. 一致性级别:SERIAL、LOCAL_SERIAL
  6. 谨慎使用:仅在必要时使用

恭喜你完成了Cassandra完全指南的学习!

最后更新:2026-03-27