MyISAM中的交易问题

时间:2010-12-18 16:29:06

标签: php mysql

这是问题所在。我在MySQL MyISAM表中有几个表。而且我有几个依赖于另一个的查询。这种东西:

CREATE TABLE users (
  name varchar(255) DEFAULT NULL PRYMARY KEY,
  money int(10) unsigned DEFAULT NULL
);
INSERT INTO users(name, money) VALUES('user1', 700);
INSERT INTO users(name, money) VALUES('user2', 200);

我需要将钱从一个用户转移到另一个用户

<?php
$query1 = "UPDATE users SET money=money-50 WHERE name = 'user1'";
$query2 = "UPDATE users SET money=money+50 WHERE name = 'user2'";

问题是如果这两个查询之间的连接断开,钱就会丢失,第一个用户丢失它们,另一个不能获得它们。我可以使用InnoDB或BDB来启动事务,并在任何一个错误中回滚两个查询,但我仍然为MyISAM 这个asignment 。 这个问题通常如何解决?

3 个答案:

答案 0 :(得分:2)

MyISAM没有提供任何内部处理机制。如果您需要原子性,请使用支持事务的引擎,例如InnoDB引擎。这是解决此类问题的常用方法。

另一种可能性是存储交易而不是总计。

CREATE TABLE users(name VARCHAR(255), PRIMARY KEY (name));
CREATE TABLE transactions(from_user VARCHAR(255), to_user VARCHAR(255), amount INT);

这意味着交易现在只是一个查询,但找到当前余额更加困难。

交易:

INSERT INTO transactions VALUES('user1', 'user2', 50);

找到平衡更难:

SELECT (SELECT SUM(amount) FROM transactions WHERE to_user='user2') - (SELECT SUM(amount) FROM transactions WHERE from_user='user2')

由于记录不能只插入一半,因此解决了这个问题。注意我没有说这是一个好主意。 使用交易数据库。

注意:还有一种方法可以做到这一点,相当丑陋,但仍然应该是MyISAM的原子。

UPDATE users SET money=IF(name='user1',money-50, money+50) WHERE name='user1' OR name='user2';

答案 1 :(得分:2)

首先,有几个人提到这不是一个好主意,你不应该在任何真实系统中这样做。但我认为这是一项家庭作业,目标是弄清楚如何在不支持它的系统中伪造原子更新。

您可以通过基本创建自己的事务日志系统来实现。这些想法是创建一组idempotent操作,即,如果它们被中断,您可以再次重复操作,并获得正确的结果。加法和减法不是幂等的,因为如果多次加或减,最终会得到不同的结果。作业是。所以你可以这样做:

CREATE TABLE transactions(
    id int auto_increment primary key,
    committed boolean default false,
    user1 varchar(255), 
    user2 varchar(255),
    balance1 int,
    balance2 int,
    index (id, committed)
);

然后你的“交易”看起来像这样:

INSERT INTO transactions(user1, user2, balance1, balance2) 
    VALUES(
        'user1', 
        'user2', 
        (SELECT money + 50 FROM users where name='user1'),
        (SELECT money - 50 FROM users where name='user2')
    );

然后您有一个提交事务的单独系统或函数。查找第一个未提交的事务,使用存储的值更新两个帐户,并将事务标记为已提交。如果流程中断,您将能够恢复,因为您可以回放交易,如果您多次回​​放交易,则不会造成任何损害。

答案 2 :(得分:-4)

UPDATE users u1
INNER JOIN users u2
SET u1.money=u1.money-50, u2.money=u2.money+50
WHERE u1.name = 'user1'
AND u2.name = 'user2'