Skip to content

Latest commit

 

History

History
78 lines (56 loc) · 3.06 KB

diesel_mysql_lock.md

File metadata and controls

78 lines (56 loc) · 3.06 KB

工程上要在用户金钱变动操作(UPDATE语句)中加上事务处理和数据库锁,Mysql提高了两种加锁的方式

  • 共享锁(S锁): 可读不可写 | SELECT ... LOCK IN SHARE MODE
  • 排他锁(X锁): 不可读不可写 | SELECT ... FOR UPDATE

Rust的diesel ORM远没有ActiveRecord强大,我照着diesel的文档/issues写了段更新用户余额的代码

diesel和rails类似(参考rails的悲观锁)

只提供了通过for update语句加锁的方式,也叫「悲观锁」

rails会将SQL语句输出,而diesel只有Postgres支持,所以只能开启MySQL的Log去确认是否加锁了。

Mysql 开启 general_log

参考Stack Overflow

sudo mkdir /var/log/mysql
sudo touch /var/log/mysql/general_log
sudo chown mysql:mysql /var/log/mysql
sudo chown mysql:mysql /var/log/mysql/general_log

mysql> SET GLOBAL general_log = 'ON';
mysql> SET GLOBAL general_log_file = '/var/log/mysql/general_log';

Rust代码,完整代码请看diesel PR#2381

fn update_user_balance_with_lock(
    ref_db_connection: &MysqlConnection,
    user_id: u32,
    new_balance: i32,
) {
    ref_db_connection.transaction::<_, diesel::result::Error, _>(|| {
        // Lock the user record to avoid modification by other threads
        users_dsl.find(user_id).for_update().execute(ref_db_connection)?;

        diesel::update(users_dsl.find(user_id))
          .set(users::account_balance.eq(new_balance))
          .execute(ref_db_connection)?;
        Ok(())
    }).unwrap();
}

这个函数对应的Mysql查询语句是

Query	BEGIN
Prepare	SELECT `users`.`id`, `users`.`account_balance` FROM `users` WHERE `users`.`id` = ? FOR UPDATE
Execute	SELECT `users`.`id`, `users`.`account_balance` FROM `users` WHERE `users`.`id` = 8 FOR UPDATE
Prepare	UPDATE `users` SET `account_balance` = ? WHERE `users`.`id` = ?
Execute	UPDATE `users` SET `account_balance` = 10 WHERE `users`.`id` = 8
Close stmt
Query	COMMIT

diesel似乎还提供了一个with_lock() API给数据库加锁,不过文档上没有例子


diesel对我PR的回复

Can you please elaborate(阐述) why this needs a distinct example in the example directory,
instead of just improving the API documentation here,
especially as this example applies to multiple backends, but is only provided for one.

虽然diesel作者拒绝了我的PR,不过我不后悔,提PR的过程中学到了不少新知识。

挺欣赏diesel作者对项目代码质量的高要求,我水平太低过不了他的review

我的英语水平、技术水平还需要质变才能参与diesel的开发。