【问题标题】:INSERT if record doesn't exist, UPDATE if exists如果记录不存在则插入,如果存在则更新
【发布时间】:2022-02-18 11:42:14
【问题描述】:

我正在尝试使用 Multivit4min (github) 的 Node.js 库制作一个 TS3 机器人 机器人应该这样做: (这里是表: 尼克 (txt)| cldbid (int)| clid(txt) |最后一个频道(整数) 顺便提一句。作为客户端ID的clid应该是客户端的唯一ID)

事件 #1 - 客户端连接到服务器:

  • 检查数据库中是否存在带有 client.UID 的记录: 是:将其 lastChannel 更新为 event.channel.channelId 否:插入 client.nick、cldbid、UID 和 event.channel.channelId

事件 #2 - 客户端移动到另一个频道:

  • 将 lastChannel 更新为 event.channel.channelId

事件 #3 - 客户端移动到特定频道:

  • 通过他的 UID 搜索记录并将他的 lastChannel 保存到一个变量中

通常我知道如何使用 Node 做部分,但我在使用 SQL 时遇到了困难,因为它总是显示一些错误或无法正常工作。

我尝试了很多查询,但没有一个有效。我所做的最好的事情是堆栈上其他线程的一些代码是“REPLACE”,它应该自动检查它是否存在然后更新或者不存在 - 然后插入。但它总是会创建越来越多的记录副本。

这是我的一些代码:

ts3.on("clientconnect", event => {
    
        sql.query("SELECT * FROM `users` WHERE `clid`= " + event.client.getUID(), 

        function(err, result){
            if(err){
                console.log(time.get() + "Error SQL: " + err)
            }else{
                if(row && row.length){
                    sql.query("REPLACE INTO users (nick, cldbid, clid, lastChannel) VALUES ('" + event.client.nickname + "','" + event.client.getDBID() + "','" + event.client.getUID() + "','" + config.lastChannel + "');",
                    function(err,result){
                        if (err){
                            console.log(time.get()+err)
                        }else{
                            console.log(time.get() + `Dodano użytkownika ${event.client.nickname} do bazy danych`)
                        }
                    })
                }
            }
        })

})

我真的不希望你为我创建完整的代码。我只是要求带有最终“ifs”的 SQL 查询,因为如您所见,我的第四个想法(我之前说过我尝试了多种方法)是基于 SELECT 并根据结果,UPDATE 或 INSERT 记录。

请随意询问有关 vars、代码等的问题,我整晚都在 ..


我想出了这样的代码:

sql.query("INSERT INTO users (nick,cldbid,clid,lastChannel) VALUES('"+event.client.nickname+"',"+event.client.getDBID()+",'"+event.client.getUID()+
        "',"+config.lastChannel+") ON DUPLICATE KEY UPDATE lastchannel="+event.channel.cid+";", 

        function(err, result){
            if(err){
                log.clog("Blad SQL #clientmoved: " + err)
            }else{
                log.clog("Pomyslnie addded/updated record of "+event.client.nickname)
            }
        })

现在我需要帮助如何将记录的 x 列中的 1 个参数保存到变量中。 (整数)

【问题讨论】:

  • ON DUPLICATE KEY UPDATE 是您正在寻找的。此外,看看准备好的陈述。你在这里留下了一个巨大的 sql 注入孔。
  • 实际上这几乎是不可能的,因为teampeak的最大昵称并不长。大多数用户甚至不知道 SQL 注入。只有 1% 的用户可以使用它,但我认为他们不会尝试使用昵称来删除在我的代码中不是严重错误的数据库,甚至不会出现小错误,因为我将使用 try{}catch(){}防止 SQL 出错。
  • 删除数据库并不是 sql 注入所能做的最糟糕的事情,它实际上是较温和的结果之一。窃取敏感的用户数据和在服务器上执行任意代码(是的,这也是可能的)是您应该担心的。至于REPLACE INTO,它需要你监控的列上的唯一键。
  • 那里的数据是公开的,ts服务器上的每个人都可以检查它,即使有人设法用node.js执行一些对我的机器不会真正有害的代码,唯一的事情我一直有这个机器人。 @Timekiller 该规则是否也适用于 DUPLICATE ON KEY ?

标签: javascript mysql sql node.js


【解决方案1】:

要回答原始问题,您需要ON DUPLICATE KEY UPDATE。更重要的是,您的代码容易受到 SQL 注入的攻击。

您不应该像这样将值直接插入到您的查询中。考虑这个例子:

db.query("INSERT INTO messages (message, username) VALUES ('" + message + "', "' + username + ')");

如果 username 是我经过身份验证的用户名,但 message 是我在 UI 中输入的任何值,我可以通过发送如下消息来假装是其他人:I am stupid', 'someone_else') --

SQL 将如下所示:

INSERT INTO messages (message, username)
VALUES ('I am stupid', 'someone_else') --', 'my_username')

--', 'my_username') 位被视为注释,因此看起来someone_else 表示I am stupid。这是 Web 应用程序中最常见且最容易利用的漏洞之一。

解决方案 1

您可以参数化您的查询:

db.query(`
  INSERT INTO messages (message, username)
  VALUES (?, ?)
`, [message, username]);

这是安全的,但更难阅读(在我看来),你必须非常小心,始终如一地这样做。

对于您的示例,如下所示:

sql.query("INSERT INTO users (nick,cldbid,clid,lastChannel) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE lastchannel=?;", 
  [event.client.nickname, event.client.getDBID(), event.client.getUID(), config.lastChannel, event.channel.cid],
        function(err, result){
            if(err){
                log.clog("Blad SQL #clientmoved: " + err)
            }else{
                log.clog("Pomyslnie addded/updated record of "+event.client.nickname)
            }
        })

解决方案 2

https://www.atdatabases.org 提供的数据库 API 相对容易使用,并且完全可以免受此类攻击。你会这样做:

import connect, {sql} from '@databases/pg';

const db = connect();

db.query(sql`
  INSERT INTO messages (message, username)
  VALUES (${message}, ${username})
`);

安全地执行相同的查询。 sql 标记确保数据得到正确处理/转义,@databases/pg 自动强制您始终添加 sql 标记。注:然后参数周围没有引号。

对于你的例子,就像

db.query(sql`INSERT INTO users (nick,cldbid,clid,lastChannel) VALUES(${event.client.nickname},${event.client.getDBID()},${event.client.getUID()},${config.lastChannel}) ON DUPLICATE KEY UPDATE lastchannel=${event.channel.cid};`).then(
  result => log.clog("Pomyslnie addded/updated record of "+event.client.nickname),
  err => log.clog("Blad SQL #clientmoved: " + err),
);

【讨论】:

    猜你喜欢
    • 2018-04-02
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 2015-03-31
    • 1970-01-01
    相关资源
    最近更新 更多