大型数据库如何处理锁?

时间:2017-01-11 06:03:05

标签: python mysql

我对数据库和更新行有疑问。

我正在运行一个烧瓶应用程序,端点运行这样的命令(请接受这种伪代码/速记语法)

select * from Accounts where used = "False"
username = (first/random row of returned set)
update Accounts set used = "True" where name = username
return username

但是,如果有100个人在同一时间对此终端点进行调用会怎么样?

我怎样才能避免出现问题? (意思是2个人没有从表中获得相同的用户名,因为更新语句还没有在第二个人查询之前运行。)

显而易见的解决方案是锁定,类似于 - 这样如果两个人在同一时间点击端点,第二个人将不得不等待锁定释放

Global lock 

----

with lock:
    select * from Accounts where used = "False"
    username = (first/random row of returned set)
    update Accounts set used = "True" where name = username
    return username

我相信这会奏效,但这不是一个很好的解决方案。有没有人对此有任何更好的想法?我确信公司在数据一致性方面始终存在这个问题,他们如何解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:2)

MySQL / InnoDB提供四个transaction isolation levelsREAD UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE

假设您使用REPEATABLE READSERIALIZABLE隔离级别在单个事务中执行所有命令,则一次只能执行一个访问相同行的事务,因此对于100个用户,只有1个用户执行该事务,而其余99个将在队列中等待。

使用READ UNCOMMITTEDREAD COMMITTED隔离级别,两个或更多用户可以在used = False时读取同一行,并尝试将其设置为used = True }。

我认为如果将数据库布局重构为两个表会更好:一个具有所有可能的名称,另一个具有使用的名称,并且名称列具有唯一约束。对于每个新用户,您都会在使用的名称表中插入一个新行。如果您尝试插入具有相同名称的多个用户,则会出现违反唯一约束的错误,并且可以使用其他名称重试。

答案 1 :(得分:2)

数据库上的全局锁定非常糟糕。他们会大大放慢一切。相反,有表锁(要避免),行锁(这些都很好)和事务。

使用transaction。这可以将您和他们的更改与您的更改隔离开来。它还允许您丢弃所有更改,回滚,如果有问题,所以您不要在中途完成更改。除非你有充分的理由,否则你应该总是在交易中。

MySQL支持SELECT FOR UPDATE,它告诉数据库您要更新此事务中的选定行,以便这些行被锁定。

使用伪代码示例...

begin transaction
select * from Accounts where used = "False" for update
username = (first/random row of returned set)
update Accounts set used = "True" where name = username
commit
return username

基本上,事务使一组SQL语句“原子化”,这意味着它们从并发使用的角度出现在单个操作中。

其他要点......您应该使用Accounts的主键进行更新,以避免使用非唯一字段。也许主键是用户名,也许不是。

其次,没有订单的选择可以按任何顺序返回。如果您正在通过一个帐户队列,您应该指定某种顺序,以确保最先完成(或您决定业务逻辑将是什么)。即使order by rand()也会比依赖默认的表排序做得更好。

最后,如果您只想获取一行,请添加limit 1,这样数据库就不会做太多额外的工作。

答案 2 :(得分:0)

首先,我要在表格中添加一个新字段,让它称之为会话ID。连接到该端点的每个客户端都应具有唯一的会话ID,sg将其与其他客户端区分开来。

我首先更新单个记录并将其会话ID字段设置为客户端的会话ID,然后检索会话ID上的记录,而不是进行选择,然后进行更新:

function aksi_login(){
    $username = $this->input->post('username');
    $password = $this->input->post('password');
    $where = array(
        'username' => $username,
        'password' => md5($password)
        );
    $result = $this->m_login->cek_login("admin",$where);
    $cek = $this->m_login->cek_login("admin",$where)->num_rows();
    if($cek > 0){
        $cek = $result->row_array();//no your records are in array format having matched row
        $data_session = array(
            'username' => $cek['username'],
            'nama'     => $cek['nama']
            'status'   => "login"
            );
        $this->session->set_userdata($data_session);
        redirect(base_url("admin"));
    }else{
        echo "Username dan password salah !";
    }
}

这样就可以避免锁定

相关问题