查看原文
其他

数据库对比系列之三(PG事务与MySQL事务)

薛晓刚 四海内皆兄弟 2023-10-17

   今天网上有个帖子,说MYSQL部分事务成功,部分事务失败。原图如下:

     我第一感觉觉得不应该。我当时也觉得这个好像按照DBA的角度来说不应该一个成功一个失败。于是我做了一个模拟。下面有两个表一个是W表有主键,为了模拟冲突。另外一个B表无约束,随便操作。

    

       开启事务,w有5条,b有2条。这个时候给b新增一条3,并且给w增加一条5(一定是冲突的)。数据库版本是MySQL8.0.26。

      

     查看一下结果,真的是W没有进去,而B有数据了。好像世界观坍塌了。和我们之前预想的不一样。这个时候我们来看看其他数据库如何?

     由于Oracle必须手工提交,所以很容易模拟。看下图b取前5条。C表建立约束,给C表先增加一条数据,准备制造冲突(绿色框)。

     红色框为事务开始,给B增加一条数据,给C也增加一条数据。C写入失败。这个时候提交。结果是B的数据进来了,C没有成功。看了Oracle也是这样的机制。好了,静心下来想想,那这么说不是BUG了。因为Oracle不可能有这样的BUG。毕竟大家都觉得Oracle这个神谕,有点像神一样的存在。


   来梳理一下为什么?假设开启事务以后,执行了SQL1,SQL2和SQL3.   SQL1成功,这个时候SQL2由于拼写或者语法错误报错执行不成功。SQL3,继续执行成功。那么提交以后会如何?这么想的话(应用程序不会犯这个错误,因为都是编译测试过的,但是人工会这样的),的确应该SQL1和SQL3 成功SQL2,拼写错了,不成功也合理。这么一想,我好想也想通了。也合理了。

那么我们来看看PG的执行。B表和C表的区别是C表的ID是主键不能冲突的。B表一条记录,C表一条记录。

红框为事务。篮框是提交,注意与其他数据库不一样的是。由于事务之间有报错,所以这个提交后,PG最终给出的不是commit,而是rollback的回退。也就是说PG最后结果走的是回退,而不是提交。所以才和MySQL不一样,当然也和Oracle不一样。这点差异最大。那么是不是只要有报错就回退呢?验证一下:故意写一个失败的SQL。

果然和预期的一样,commit后执行器觉得中间有报错,没有走提交的路线,而是执行了回退。

到这里就明白了。PG在事务中不允许有任何出错,哪怕是拼写错误。否则都会全体回退。这个对于经验丰富的人来说这没什么,而对于我们这种公司没有PG、没有TiDB,只是凭借职业热情来说的人还是很新鲜的。

      这里我对比了PostgreSQL和MySQL Oracle在事务中对错误的分析。看到了PG对事务中出错的0容忍。也许这些都可以通过参数修改,我还没研究到。这里没有谁对谁错。只是处理的方式不同。OracleMySQL事务中由于拼写、约束等导致的失败的就失败了(约束限制,而PG这里是强制回退)。提交那些提交成功的。如果回退则是全体回退,(执行失败的无需回退)



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存