Javascript 如果记录不存在则插入,如果存在则更新

Javascript 如果记录不存在则插入,如果存在则更新,javascript,mysql,sql,node.js,Javascript,Mysql,Sql,Node.js,我正在尝试从Multivit4min github使用Node.js库制作一个TS3机器人 bot应该这样做: 这是桌子: nick txt | cldbid int | clidtxt | lastChannel int 顺便说一句,clid是客户端id,应该是客户端的唯一id 事件1-客户端连接到服务器: -检查数据库中是否存在client.UID记录: 是:将其最后一个频道更新为event.channel.channelId 否:插入client.nick、cldbid、UID和event

我正在尝试从Multivit4min github使用Node.js库制作一个TS3机器人 bot应该这样做: 这是桌子: nick txt | cldbid int | clidtxt | lastChannel int 顺便说一句,clid是客户端id,应该是客户端的唯一id

事件1-客户端连接到服务器: -检查数据库中是否存在client.UID记录: 是:将其最后一个频道更新为event.channel.channelId 否:插入client.nick、cldbid、UID和event.channel.channelId

事件2-客户端移动到另一个通道: -将lastChannel更新为event.channel.channelId

事件3-客户端移动到特定通道: -按他的UID搜索记录,并将其最后一个频道保存到变量中

一般来说,我知道如何使用Node进行部分操作,但我很难使用SQL,因为它总是显示一些错误或不能正常工作

我试过很多问题,但都不管用。我所做的最好的事情就是从堆栈上的其他线程中得到一些代码,这些代码是“替换”的,它应该自动检查它是否存在,然后更新,或者如果不存在,然后插入。但它总是在创造越来越多的记录副本

以下是我的一些代码:

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`)
                        }
                    })
                }
            }
        })

})
我真的不希望你为我创建完整的代码。我只是要求SQL查询具有最终的ifs,因为正如您所看到的,我之前说过的第四个想法,我尝试了许多方法,基于SELECT并根据结果更新或插入记录


请随意询问变量、代码等,我花了整整一个晚上。

我想出了如下代码:

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列保存到变量。int

要回答原始问题,您需要重复密钥更新。但更重要的是,您的代码容易受到SQL注入的攻击

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

db.query("INSERT INTO messages (message, username) VALUES ('" + message + "', "' + username + ')");
如果用户名是我经过身份验证的用户名,但消息是我在UI中键入的任何值,我可以通过发送类似“我很笨”、“其他人”的消息来假装是其他人-

SQL将如下所示:

INSERT INTO messages (message, username)
VALUES ('I am stupid', 'someone_else') --', 'my_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)
            }
        })
-','my_username'位被视为一条评论,因此看起来好像有人说我很愚蠢。这是web应用程序中最常见且易于利用的漏洞之一

解决方案1 您可以将查询参数化:

db.query(`
  INSERT INTO messages (message, username)
  VALUES (?, ?)
`, [message, username]);
这是安全的,但在我看来更难理解,你必须非常小心,始终坚持这样做

对于您的示例,这看起来像:

INSERT INTO messages (message, username)
VALUES ('I am stupid', 'someone_else') --', 'my_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 提供相对易于使用且完全安全的数据库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),
);

重复密钥更新是您需要的。此外,请看准备好的声明。您在这里留下了一个巨大的sql注入漏洞。实际上它几乎不可能复制,因为teamspeak上的最大昵称并不长。大多数用户甚至不知道SQL注入。只有1%的用户可以使用它,但我不认为他们会尝试使用昵称来删除数据库,这在我的代码中不是关键错误,甚至不是小错误,因为我将使用try{}catch{}来防止SQL出错。删除数据库到目前为止不是SQL注入可以做的最糟糕的事情,实际上这是一个比较温和的结果。窃取敏感用户数据和在服务器上执行任意代码是的,这也是您应该担心的。至于REPLACE-INTO,它需要在您监视的列上有一个唯一的键。那里的数据是公共的,ts服务器上的每个人都可以检查它,而且即使有人会设法使用node.js执行一些不会对我的机器造成真正伤害的代码,我唯一保存在那里的就是这个bot@Timekiller该规则是否也适用于键上重复?