我正在用C开发一个系统,它将更新提交到MySQL数据库中。客户端并不总是在线,因此当服务器不可访问时,应用程序将保存将执行到* .sql的SQL命令。
我正在考虑将一个名为late_commit
的BOOLEAN字段添加到所使用的表中,以便我知道稍后在恢复连接时将这些字段插入到数据库中。
我可以改变程序中的编程逻辑,在插入查询中包含late_commit
字段,但我宁愿使用默认值false,并且只有在.sql时才设置为true文件被执行。
我想过使用alter语句插入插入内容,但这看起来有点笨拙并且性能会很差。
我从来没有使用触发器,但是从我在SO question中看到的它们可以起作用。但是,它们似乎不是临时的或本地会话,这会干扰来自其他客户端的并发插入。
你对自己的表现有什么看法吗?不一定是要使用的查询,而是应用最佳的技术/方法。
编辑:
我认为,如果没有其他方法出现,可以创建一个具有相同结构且late_commit
默认为true的临时表,将数据插入其中,然后复制到主表中。
注意: 我已经添加了一些我找到的方法的答案。我仍然在寻找永久的解决方案。所以请如果你知道如何做得更好,请发表评论或回答。谢谢!
答案 0 :(得分:1)
我会为false
设置默认late_commit
并让所有普通代码忽略它的存在。然后我会将编写SQL文件的代码通过注入late_commit内容的“装饰器”,例如普通的SQL:
insert into table1 (col1, col2) values (val1, val2);
但是当写入档案时:
insert into table1 (late_commit, col1, col2) values (true, val1, val2);
这样只需要知道一段代码。 SQL解析以确定将额外位放在何处非常简单。
答案 1 :(得分:0)
我想我会离开这里,到目前为止我发现的是为了回答这个问题。
正如问题所述,我最好只选择sql方法,避免使用注射器。 准备好的语句不起作用,因为它们需要连接到可能不存在的数据库。
IFNULL()解决方案:
我倾向于使用我提出的使用IFNULL mysql语句的解决方案,通过设置局部变量,我可以在进行实际操作时使用相同的查询配置late_commit
列(late_commit
= false)或稍后进行(late_commit
= true)。
所以使用查询:
INSERT INTO `tmp`.`new_table` (`a`,`b`,`late_commit`)
VALUES ('abc','def', IFNULL(@LATECOMMIT, FALSE) );
我可以插入late_commit
列设置为false的值,使用IFNULL语句:因为未定义会话变量@latecommit
,代码会将列配置为false。
另一方面,如果我们实际上正在进行离线提交,我们只需要在所有插入之前加上:
SET @LATECOMMIT = TRUE;
然后继续进行所有必要的插入,在我的例子中包含几个不同的表,但在所有这些表中都有late_commit
字段设置为IFNULL(@LATECOMMIT, FALSE)
:
INSERT INTO `tmp`.`new_table` (`a`,`b`,`latecommit`)
VALUES ('abc','def', IFNULL(@LATECOMMIT, FALSE) );
我喜欢这个解决方案,因为变量只为当前会话设置,并且很容易实现(例如,您只需在SET指令前面添加.sql文件并继续执行)。
TIMEDIFF()或时间戳减法解决方案:
在聊天中讨论这个问题时,@ TehShrike还为我提供了一个仅限sql的解决方案,我利用了首次生成查询的时间和插入时间之间的差异。
这可以完成,因为我的表实际上插入的是clientdate
时间戳变量,这是本地的unix时间戳。
所以对于这个解决方案,所需要的只是确定什么被认为是late_commit
(例如60秒,1小时......),然后像我这样插入:
INSERT INTO `tmp`.`new_table` (`a`,`b`,`clientdate`,`latecommit`)
VALUES ('abc','def', FROM_UNIXTIME(1313489338),
IF( CURRENT_TIMESTAMP() - clientdate > 3600, TRUE, FALSE) );
在此插入中,我们认为超过一小时前(3600秒)生成的插入为late_commit
。
如果您没有使用时间戳,您也可以使用日期时间字段,在这种情况下您可能会使用DATEDIFF()或TIMEDIFF()函数。