Tranh chấp tài nguyên(DeadLock) trong MySQL và cách xử lý

Tranh chấp tài nguyên trong MySQL xảy ra khi nhiều yêu cầu đồng thời truy cập cùng một tài nguyên, chẳng hạn như một bảng hoặc một hàng dữ liệu trong cùng một bảng. Điều này có thể dẫn đến xung đột, lỗi hoặc giảm hiệu suất.

Các cách xử lý tranh chấp tài nguyên trong MySQL bao gồm:

Cách 1: Sử dụng bảng phụ (partitioned table): Bạn có thể chia nhỏ một bảng lớn thành nhiều bảng nhỏ hơn để giảm số lượng yêu cầu đồng thời truy cập cùng một tài nguyên.

CREATE TABLE order_history (
  order_id INT,
  order_date DATE,
  product VARCHAR(255),
  quantity INT
)
PARTITION BY RANGE (order_date) (
  PARTITION p0 VALUES LESS THAN ('2020-01-01'),
  PARTITION p1 VALUES LESS THAN ('2020-02-01'),
  PARTITION p2 VALUES LESS THAN ('2020-03-01')
);

Trong ví dụ này, chúng ta đã tạo một bảng đơn hàng với cột order_date làm cơ sở để phân chia bảng thành các bảng phụ. Khi truy vấn dữ liệu, chúng ta sẽ chỉ truy vấn dữ liệu trong bảng phụ tương ứng, giảm thiểu tải trên bảng gốc và tăng tốc độ truy vấn.

Cách 2: Sử dụng từ khóa FOR UPDATE: Bạn có thể sử dụng từ khóa FOR UPDATE để yêu cầu một truy vấn chờ cho đến khi một tài nguyên được cập nhật xong.

BEGIN;
SELECT * FROM users WHERE user_id = 123 FOR UPDATE;
UPDATE users SET balance = balance - 100 WHERE user_id = 123;
COMMIT;

Trong ví dụ này, chúng ta sử dụng lock đồng bộ để xác định rằng chỉ có một yêu cầu có thể truy cập và cập nhật dữ liệu của user_id 123 cùng lúc.

Cách 3: Sử dụng (transaction) . Ban có thể đưa câu truy vấn và transaction để bảo toàn tính nhất quán của dữ liệu

START TRANSACTION;
SELECT * FROM users WHERE user_id = 123;
UPDATE users SET balance = balance - 100 WHERE user_id = 123;
COMMIT;

Trong ví dụ này, chúng ta sử dụng transaction để bảo toàn tính nhất quán của dữ liệu trong quá trình truy cập và cập nhật dữ liệu của user_id 123.

Cách 4: Sử dụng cấu hình ưu tiên: Bạn có thể để đảm bảo rằng các yêu cầu truy cập tài nguyên được xử lý theo thứ tự ưu tiên xác định.

SET GLOBAL innodb_priority_thread = 2;
SELECT * FROM users WHERE user_id = 123;
UPDATE users SET balance = balance - 100 WHERE user_id = 123;
SET GLOBAL innodb_priority_thread = 0;

Cách 5: Sử dụng chế độ đồng bộ hóa (synchronization mode): Bạn có thể sử dụng chế độ đồng bộ hóa để đảm bảo rằng các yêu cầu truy cập tài nguyên được xử lý theo thứ tự xác định. Điều này có thể giúp tránh xung đột tài nguyên và đảm bảo tính nhất quán của dữ liệu.

var mysql = require('mysql');

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : 'password',
  database : 'test'
});

connection.connect();

connection.beginTransaction({
  isolationLevel: 'SERIALIZABLE'
}, function (error) {
  if (error) { throw error; }
  connection.query('SELECT balance FROM users WHERE user_id = 123', function (error, results, fields) {
    if (error) {
      return connection.rollback(function () {
        throw error;
      });
    }
    console.log('User balance is: ', results[0].balance);

    var newBalance = results[0].balance - 100;
    connection.query('UPDATE users SET balance = ' + newBalance + ' WHERE user_id = 123', function (error, results, fields) {
      if (error) {
        return connection.rollback(function () {
          throw error;
        });
      }
      console.log('The user balance has been updated to: ', newBalance);
      connection.commit(function (error) {
        if (error) {
          return connection.rollback(function () {
            throw error;
          });
        }
        console.log('Transaction completed.');
      });
    });
  });
});

connection.end();

Trong ví dụ này, chúng ta sử dụng chế độ đồng bộ hóa (SERIALIZABLE) để đảm bảo việc truy cập và cập nhật dữ liệu được thực hiện một cách đồng bộ. Điều này giúp tránh trường hợp hai hoặc nhiều yêu cầu truy cập cùng một lúc dẫn đến việc cập nhật sai dữ liệu.

Cách 6: Sử dụng giao diện API: Bạn có thể sử dụng giao diện API để gửi yêu cầu tới MySQL và tránh việc truy cập trực tiếp tài nguyên. Điều này có thể giúp giảm số lượng yêu cầu đồng thời truy cập cùng một tài nguyên và giảm xung đột tài nguyên.

var mysql = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : 'password',
  database : 'database_name'
});

connection.connect();

connection.query('SELECT * FROM users WHERE user_id = 123', function (error, results, fields) {
  if (error) throw error;
  console.log('The user balance is: ', results[0].balance);

  var newBalance = results[0].balance - 100;
  connection.query('UPDATE users SET balance = ' + newBalance + ' WHERE user_id = 123', function (error, results, fields) {
  if (error) throw error;
  console.log('The user balance has been updated to: ', newBalance);
 });
});

connection.end();

Trong ví dụ này, chúng ta sử dụng giao diện API để truy cập và cập nhật dữ liệu từ database. Chúng ta có thể sử dụng hàm callback để xử lý kết quả trả về từ database và thực hiện các tác vụ tiếp theo.

Trong tất cả các trường hợp, quan trọng nhất là phải đảm bảo rằng các yêu cầu truy cập tài nguyên được xử lý một cách hiệu quả và tính nhất quán của dữ liệu được bảo toàn.

Leave a Comment