2017-02-13 125 views
0

我正在从事金融系统工作,并且遇到了MySQL事务的问题。MySQL事务回滚没有ROLLBACK查询?

该系统是一个简单的证券交易所,用户可以在其中购买和出售虚拟股票。为了保持购买和销售过程的完整性,我使用交易。 问题是,在某些情况下(我不知道它依赖于什么)一些事务回滚(或未提交),但是下一个查询被处理。

的过程如下:

  1. 用户希望购买的股票为1000美元
  2. 在订单量有4个报价为250美元
  3. START TRANSACTION
  4. 对于每一个报价:
  5. 脚本进行UPDATE查询(将美元从一个用户转移到另一个用户,并以相反方式分享)。然后脚本将条目插入到历史记录表中。
  6. 用户支付费用(更新余额)。
  7. 对下一个报价重复5和6。
  8. COMMIT

现在关键的部分 - 在某些情况下,从5点不保存更改,而是从6他们(我看到费已支付,但在历史上没有交易)。 在此交易中,我没有使用ROLLBACK,并且脚本没有中断(因为在这种情况下,费用不会被支付)。

查询有没有可能回滚没有ROLLBACK?或者MySQL可以只提交几个最新的查询而不是全部?

非常感谢您的回复。

+1

不,交易应该始终是原子的。要么它什么都不做或什么都不做。 – Barmar

+0

系统中的第一个漏洞是您在交易之前检查订单(仅),因此可能已更改;例如订单1可能已被使用,只剩下3个开放优惠,根据您的实际代码,第5步可能不会做任何事情,但第6步可能仍然收取费用。但这只是一个问题,只有你的概念。还有很多其他的事情你可以做错(例如使用myisam,使用错误的事务级别,不锁定选择,...),所以这里可能还有其他问题。如果你用真实的金钱/价值进行交易,你应该找一位顾问来检查你的代码。 – Solarflare

+0

我没有在第一篇文章中写过(对不起),但是我在启动过程之前使用'SELECT FOR UPDATE'锁定行。 当我处理单个优惠时,我正在检查另外一项,如果优惠仍然存在,用户有有效余额等。 但是目前它是演示系统。 – Zachmian

回答

0

事务与否,您的客户端代码的责任是确保您的所有INSERT或UPDATE查询成功完成,然后发出明确的ROLLBACK或用COMMIT关闭连接以发出隐含的ROLLBACK。如果它们中的任何一个失败,但是你的代码继续执行,那么这些查询将不会生效(因为它们失败了),但其余的都会执行。

这里有一个简单的例子:

mysql> create table test (
    ->  id int(10) unsigned not null, 
    ->  primary key (id) 
    ->); 
Query OK, 0 rows affected (0.02 sec) 

mysql> insert into test(id) values (1); 
Query OK, 1 row affected (0.00 sec) 

mysql> start transaction; 
Query OK, 0 rows affected (0.00 sec) 

mysql> insert into test(id) values (2); 
Query OK, 1 row affected (0.00 sec) 

mysql> insert into test(id) values (-3); 
ERROR 1264 (22003): Out of range value for column 'id' at row 1 

我们应该rollbacked这里中止,但我们没有。

mysql> insert into test(id) values (4); 
Query OK, 1 row affected (0.00 sec) 

mysql> commit; 
Query OK, 0 rows affected (0.00 sec) 

mysql> select * from test; 
+----+ 
| id | 
+----+ 
| 1 | 
| 2 | 
| 4 | 
+----+ 
3 rows in set (0.00 sec) 

4行预期,得到了3

除此之外,还有许多是情况,您可以得到不必要的COMMIT但不希望ROLLBACK是什么我不知道,可以发生,除非你用未决更改终止会话。