Nodejs操作mysql库有没有sql锁

Nodejs操作mysql库有没有sql锁

有这么个情况,我要在很多情况下进行 truncate table --> insert table(这两部是顺序执行的),问题是如果有多次同时进行这两步操作时,mysql会告诉我主键已经存在了。也就是同时出现了insert table的情况,有没有办法避免呢?最好是有正规些的解决办法。

我目前做的处理时把多次同时进行这两步操作改成了加入循环队列,一次执行完才会执行下一次,类似于node.js本身的事件轮询。但是我总觉得这样做不是很正规,因为这个问题是由于mysql的并发造成的,而不是node.js。

4 回复

Node.js 操作 MySQL 库中的 SQL 锁问题

问题描述

在使用 Node.js 操作 MySQL 数据库时,遇到一个并发问题:在同时执行 truncate tableinsert into table 操作时,可能会出现主键冲突(例如,多个 insert 操作尝试插入相同的主键值)。你希望找到一种正规的方式来避免这种情况。

解决方案

MySQL 提供了多种锁定机制来解决并发问题。在你的场景中,可以考虑使用事务(Transactions)和行级锁定(Row-Level Locking)来确保数据的一致性和完整性。

示例代码
  1. 使用事务

    事务可以帮助你在一组操作中保持一致的状态。如果你在一个事务中执行 truncate tableinsert into table,MySQL 会确保这两个操作要么都成功,要么都不执行。

    const mysql = require('mysql');
    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'testdb'
    });
    
    connection.connect((err) => {
        if (err) throw err;
        console.log('Connected!');
    });
    
    function executeTransaction() {
        connection.beginTransaction((err) => {
            if (err) {
                throw err;
            }
    
            // 执行 truncate table
            connection.query('TRUNCATE TABLE your_table', (err, result) => {
                if (err) {
                    return connection.rollback(() => {
                        throw err;
                    });
                }
    
                // 执行 insert into table
                connection.query('INSERT INTO your_table (column1, column2) VALUES (?, ?)', ['value1', 'value2'], (err, result) => {
                    if (err) {
                        return connection.rollback(() => {
                            throw err;
                        });
                    }
    
                    // 提交事务
                    connection.commit((err) => {
                        if (err) {
                            return connection.rollback(() => {
                                throw err;
                            });
                        }
                        console.log('Transaction completed successfully.');
                    });
                });
            });
        });
    }
    
    executeTransaction();
    
  2. 使用行级锁定

    如果你希望在特定记录上加锁,可以在 SELECT 语句中使用 FOR UPDATE 来锁定记录,直到事务结束。

    const mysql = require('mysql');
    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'testdb'
    });
    
    connection.connect((err) => {
        if (err) throw err;
        console.log('Connected!');
    });
    
    function executeLockedInsert() {
        connection.beginTransaction((err) => {
            if (err) {
                throw err;
            }
    
            // 加锁 select
            connection.query('SELECT * FROM your_table WHERE id = ? FOR UPDATE', [yourId], (err, rows) => {
                if (err) {
                    return connection.rollback(() => {
                        throw err;
                    });
                }
    
                // 执行 insert into table
                connection.query('INSERT INTO your_table (column1, column2) VALUES (?, ?)', ['value1', 'value2'], (err, result) => {
                    if (err) {
                        return connection.rollback(() => {
                            throw err;
                        });
                    }
    
                    // 提交事务
                    connection.commit((err) => {
                        if (err) {
                            return connection.rollback(() => {
                                throw err;
                            });
                        }
                        console.log('Transaction completed successfully.');
                    });
                });
            });
        });
    }
    
    executeLockedInsert();
    

通过使用事务和行级锁定,你可以有效地避免并发操作导致的主键冲突问题。这两种方法都可以确保你的操作在多线程环境下的一致性。


是你的并发吧,

mysql.query(truncate table, function () {
    mysql.query(insert table, function () {

}); })

不是这个意思,是多个高频率的重复你的代码,这个操作都是异步的,mysql可能会有并发啊,

在Node.js中操作MySQL数据库时,确实可能会遇到并发操作导致的数据冲突问题,例如你在truncate表之后紧接着插入数据时遇到的主键冲突问题。

解决方案

使用事务(Transaction)

MySQL支持事务处理,可以在一个事务中完成truncate和insert操作,确保它们作为一个整体被原子性地执行。事务能够保证数据的一致性和完整性。

const mysql = require('mysql');

// 创建数据库连接
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'yourusername',
  password: 'yourpassword',
  database: 'yourdatabase'
});

connection.connect();

// 开启事务
connection.beginTransaction(function(err) {
  if (err) throw err;

  // 执行truncate操作
  connection.query('TRUNCATE TABLE your_table', function(err, result) {
    if (err) {
      return connection.rollback(function() {
        console.error('Error occurred during TRUNCATE:', err);
      });
    }

    // 执行insert操作
    connection.query('INSERT INTO your_table SET ?', { column1: 'value1', column2: 'value2' }, function(err, result) {
      if (err) {
        return connection.rollback(function() {
          console.error('Error occurred during INSERT:', err);
        });
      }
      
      // 提交事务
      connection.commit(function(err) {
        if (err) {
          return connection.rollback(function() {
            console.error('Failed to commit transaction:', err);
          });
        }
        
        console.log('Transaction completed successfully');
        connection.end();
      });
    });
  });
});

使用锁(Locks)

如果你需要更细粒度的控制,可以考虑使用行级锁定或者表级锁定。但是这通常适用于更复杂的场景,例如多用户并发更新同一行数据时。

总结

使用事务是处理这种问题最正规且推荐的方法。它可以确保一系列操作要么全部成功,要么全部失败,并且保持数据库的一致性。

这样处理后,即使有多次同时进行truncate和insert操作,也能保证数据的完整性和一致性。

回到顶部