首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >跨多种技术的ACID事务

跨多种技术的ACID事务
EN

Stack Overflow用户
提问于 2020-03-13 01:56:53
回答 2查看 94关注 0票数 0

我有一个应用程序,它使用本地数据库和远程数据库进行同步。本地数据库使用SQLite,对于远程数据库,我使用postgres。我需要将数据从一个数据库移动到另一个数据库,并避免重复信息。

我现在要做的大致如下:

代码语言:javascript
复制
BEGIN;                                       //remote database  (start transaction)
SELECT * FROM local.queued TOP 1;            //local database   (select first queued element)
INSERT INTO remote.queued VALUES ( element ) //remote database  (insert first queued element on remote database)
BEGIN;                                       //local database   (start transaction)
DELETE * FROM local.queued LIMIT 1;          //local database   (delete first queued element on local database)
END;                                         //local database   (finalize transaction local database)
END;                                         //remote database  (finalize transaction remote database)

这在大多数情况下工作得相对较好,但顺便说一句,在对程序进行硬重置后,我注意到数据记录被复制了。我相信这与交易的最终完成有关。因为我使用了两种不同的技术,所以不可能使用WAL归档创建单个原子提交。

任何想法,我可以改进这个概念,以避免重复输入。

EN

回答 2

Stack Overflow用户

发布于 2020-03-13 05:10:50

执行此操作的规范方法是使用两阶段提交协议的分布式事务。

不幸的是,SQLite似乎不支持它,但由于PostgreSQL支持,如果只涉及两个数据库,您仍然可以使用它:

代码语言:javascript
复制
BEGIN;  -- on PostgreSQL

              BEGIN;  -- on SQLite

   /*
    * Do work on both databases.
    * On error, ROLLBACK both transactions.
    */

PREPARE TRANSACTION 'somename';  -- PostgreSQL

              COMMIT;  -- SQLite

COMMIT PREPARED 'somename';  -- PostgreSQL

现在,如果在SQLite COMMIT期间发生错误,您可以在PostgreSQL上运行ROLLBACK PREPARED 'sonename'。其思想是,在提交期间可能失败的所有事情都在PREPARE TRANSACTION期间完成,事务的状态被持久化,以便它保持打开状态,但在服务器重新启动后仍然可以存活。

这是安全的,但有一个警告。准备好的事务是危险的,因为它们将持有锁并阻止VACUUM清理(就像所有其他事务一样),但它们是持久的,并且会一直存在,直到您显式地删除它们。因此,您需要一些软件,一个分布式事务管理器,它是崩溃安全的,并跟踪所有分布式事务。此事务管理器可以在一些中断后清理所有准备好的事务。

票数 1
EN

Stack Overflow用户

发布于 2020-03-13 02:05:36

我认为让您的DML操作幂等是有意义的-也就是说,如果您多次调用它们,它们具有相同的整体效果。例如,如果数据存在,我们可以将INSERT设为无操作:

代码语言:javascript
复制
INSERT INTO x(id, name)
SELECT nu.id, nu.name
FROM
  (SELECT 1 as id, 'a' as name) as nu
  LEFT JOIN x ON nu.id = x.id
WHERE
  x.id IS NULL

您可以任意多次运行此命令,并且它只会插入一条记录

https://www.db-fiddle.com/f/nbHmy3PVDQ3RrGMqLni1su/0

你需要决定如果记录以改变的状态存在时该怎么做--例如,你想让它保持原样,还是将它重置为传入的值--这是另一次的问题

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60659534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档