【问题标题】:MySQL set a field value for all INSERTS during the current sessionMySQL 在当前会话期间为所有 INSERTS 设置一个字段值
【发布时间】:2011-08-09 09:36:50
【问题描述】:

我正在用 C 语言开发一个将更新提交到 MySQL 数据库的系统。客户端并不总是在线,因此应用程序会将在服务器无法访问时执行的 SQL 命令保存到 *.sql 中。

我正在考虑在使用的表中添加一个名为 late_commit 的 BOOLEAN 字段,以便稍后在恢复连接时知道这些字段已插入到数据库中。

我可以更改程序中的编程逻辑以在插入查询中包含 late_commit 字段,但我宁愿将其设置为默认值 false 并且仅在 .sql 文件为被执行。

我想过用 alter 语句插入插入,但这似乎有点笨拙,并且会提供较差的性能。

我从未使用过触发器,但从我在此 SO question 中看到的情况来看,它们可以工作。但是,它们似乎不是临时的或会话本地的,这会干扰来自其他客户端的并发插入。

您对自己如何/将如何做到这一点有任何想法吗?不一定是要使用的查询,而是最适用的技术/方法。

编辑: 我认为如果没有其他解决方案,可能是创建一个具有相同结构且late_commit 默认为 true 的临时表,将数据插入其中,然后复制到主表中。

注意: 我用我找到的一些方法添加了答案。不过,我仍在寻找永久解决方案。所以请如果您知道如何做得更好,请发表评论或回答。谢谢!

【问题讨论】:

  • 你可以使用准备好的语句吗?强烈建议多次插入,您可以将新字段的值设置为true
  • @Dor 我可以使用准备好的语句,总是在 java 中使用,但我对它在 c api 上采用的所有绑定语句有点不知所措。但请记住,如果我确实准备了语句,我仍然无法执行它,因为那时网络出现故障,也许可以在不执行的情况下提取准备好的语句,我会检查api。 - 这就是客户端无法连接到服务器的事实,这就是为什么我想将语句保存到一个 sql 文件中,以便系统稍后在连接恢复后执行。

标签: mysql


【解决方案1】:

我将为late_commit 设置默认的false,并让所有正常代码忽略它的存在。然后,我会让将 SQL 写入文件的代码通过注入late_commit 内容的“装饰器”,例如普通 SQL:

insert into table1 (col1, col2) values (val1, val2);

但是当写入文件时:

insert into table1 (late_commit, col1, col2) values (true, val1, val2);

这样只有一段代码需要知道它。用于确定将额外位放在何处的 SQL 解析相当简单。

【讨论】:

  • 当你说装饰器时,你的意思是使用 sql 字符串,类似于搜索和替换函数?
  • 是的 - 我的意思是一些 C 代码,它操纵 sql 字符串在将其写入文件时放入额外的位。
【解决方案2】:

我想我会留下到目前为止我发现的东西来回答这个问题。

如问题中所述,我更希望采用仅 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) );

我可以使用 IFNULL 语句插入 late_commit 列设置为 false 的值:因为会话变量 @latecommit 未定义,代码会将列配置为 false。

另一方面,如果我们实际上是在进行离线提交,我们只需要在所有插入之前添加:

SET @LATECOMMIT = TRUE;

然后继续进行所有必要的插入,在我的例子中包括几个不同的表,但在所有这些表中都有一个设置为 IFNULL(@LATECOMMIT, FALSE)late_commit 字段:

INSERT INTO `tmp`.`new_table` (`a`,`b`,`latecommit`)
VALUES ('abc','def', IFNULL(@LATECOMMIT, FALSE) );

我喜欢这个解决方案,因为该变量只为当前会话设置,而且它很容易实现(例如,您只需在 .sql 文件前面加上 SET 指令并继续执行它)。


TIMEDIFF() 或时间戳减法解决方案:

在聊天中讨论这个问题时,@TehShrike 还为我提供了一个纯 sql 的解决方案,我利用了查询首次生成时间和插入时间之间的差异。

可以这样做是因为我的表实际上是使用 clientdate 时间戳变量插入的,这是本地 unix 时间戳。

所以对于这个解决方案,所有需要的是确定什么会被认为是 late_commit(例如 60 秒、一小时、..),然后像这样进行插入:

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() 函数。

【讨论】:

    猜你喜欢
    • 2011-07-24
    • 2016-09-29
    • 1970-01-01
    • 2012-12-21
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    相关资源
    最近更新 更多