Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Giao dịch MySQL:CHỌN + CHÈN

Những gì bạn cần là khóa . Các giao dịch thực sự "không hoàn toàn cần thiết".

Bạn có thể chọn giữa "khóa bi quan" và "khóa lạc quan". Quyết định về một trong hai khả năng này là tùy thuộc vào bạn và phải được đánh giá cơ bản xem xét:

  • mức độ đồng thời mà bạn có
  • khoảng thời gian của các phép toán nguyên tử trên cơ sở dữ liệu
  • mức độ phức tạp của toàn bộ hoạt động

Tôi sẽ khuyên bạn nên đọc hai điều này để xây dựng ý tưởng về những điều liên quan:

Một ví dụ để giải thích rõ hơn

Điều này có thể không quá thanh lịch nhưng chỉ là một ví dụ cho thấy cách có thể thực hiện tất cả mà không cần giao dịch (và thậm chí không có ràng buộc DUY NHẤT). Điều cần làm là sử dụng trạng thái INSERT + SELECT kết hợp sau đây và sau khi thực thi nó để kiểm tra số lượng hàng bị ảnh hưởng. Nếu số lượng hàng bị ảnh hưởng là 1 thì nó đã vượt qua cách khác (nếu nó là 0) đã xảy ra va chạm và bên kia đã thắng.

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT @startTime, @endTime, @uid, @group, @message, @deviceId
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= @endTime AND `end` >= @startTime
    AND `devices_id` = @deviceId)
GROUP BY (1);

Đây là một ví dụ về tính năng Optimistic Locking thu được mà không cần giao dịch và chỉ với một thao tác SQL.

Khi nó được viết, nó có vấn đề là cần phải có ít nhất một hàng đã có trong slot để nó hoạt động (mặt khác, mệnh đề SELECT sẽ luôn trả về một tập bản ghi trống và trong trường hợp đó, không có gì được chèn vào nếu không có xung đột. Có hai khả năng để làm cho nó thực sự hoạt động:

  • chèn một hàng giả vào bảng có thể có ngày trong quá khứ
  • viết lại để mệnh đề FROM chính tham chiếu đến bất kỳ bảng nào có ít nhất một hàng hoặc tốt hơn là tạo một bảng nhỏ (có thể được đặt tên là dummy ) chỉ với một cột và chỉ một bản ghi trong đó và viết lại như sau (lưu ý rằng không cần mệnh đề GROUP BY nữa)

    INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
    SELECT @startTime, @endTime, @uid, @group, @message, @deviceId
    FROM `dummy`
    WHERE NOT EXISTS (
        SELECT `id` FROM `slot`
        WHERE `start` <= @endTime AND `end` >= @startTime
        AND `devices_id` = @deviceId);
    

Dưới đây là một loạt các hướng dẫn mà nếu bạn chỉ cần sao chép / dán sẽ cho thấy ý tưởng đang hoạt động. Tôi đã giả định rằng bạn mã hóa ngày / giờ trên các trường int dưới dạng một số với các chữ số của ngày và giờ được ghép nối với nhau.

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
VALUES (1008141200, 1008141210, 11, 2, 'Dummy Record', 14)

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141206, 1408141210, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141210 AND `end` >= 1408141206
    AND `devices_id` = 14)
GROUP BY (1);

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141208, 1408141214, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141214 AND `end` >= 1408141208
    AND `devices_id` = 14)
GROUP BY (1);

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT 1408141216, 1408141220, 11, 2, 'Hello', 14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141220 AND `end` >= 1408141216
    AND `devices_id` = 14)
GROUP BY (1);

SELECT * FROM `slot`;

Đây rõ ràng là một ví dụ cực đoan về Khóa lạc quan nhưng cuối cùng lại rất hiệu quả vì tất cả được thực hiện chỉ với một lệnh SQL và với sự tương tác thấp (trao đổi dữ liệu) giữa máy chủ cơ sở dữ liệu và mã php. Hơn nữa, thực tế không có khóa "thực".

... hoặc với Khóa bi quan

Cùng một mã có thể trở thành một cách triển khai Khóa Pessimistc tốt chỉ xung quanh với hướng dẫn khóa / mở khóa bảng rõ ràng:

LOCK TABLE slot WRITE, dummy READ;

INSERT INTO `slot` (`start`, `end`, `uid`, `group`, `message`, `devices_id`)
SELECT @startTime, @endTime, @uid, @group, @message, @deviceId
FROM `dummy`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= @endTime AND `end` >= @startTime
    AND `devices_id` = @deviceId);

UNLOCK TABLES;

Tất nhiên trong trường hợp này (Khóa bi quan) SELECT và INSERT có thể được tách biệt và một số mã php được thực thi ở giữa. Tuy nhiên, mã này vẫn thực thi rất nhanh (không có trao đổi dữ liệu với php, không có mã php trung gian) và do đó, thời gian của Khóa bi quan là ngắn nhất có thể. Giữ Khóa bi quan càng ngắn càng tốt là điểm quan trọng để tránh làm chậm ứng dụng.

Dù sao, bạn cũng cần kiểm tra giá trị trả về của bản ghi bị ảnh hưởng để biết liệu nó có thành công hay không vì mã thực tế giống nhau và do đó bạn nhận được thông tin thành công / thất bại theo cách tương tự.

Đây http://dev.mysql.com/doc/ refman / 5.0 / vi / insert-select.html họ nói rằng "MySQL không cho phép chèn đồng thời cho các câu lệnh INSERT ... SELECT" vì vậy không cần đến Khóa bi quan nhưng dù sao thì đây cũng có thể là một lựa chọn tốt nếu bạn nghĩ rằng điều này sẽ thay đổi trong các phiên bản MySQL trong tương lai.

Tôi là "Lạc quan" rằng điều này sẽ không thay đổi;-)




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tạo biến bảng trong MySQL

  2. thiết kế cơ sở dữ liệu liên quan đến thuộc tính thời gian

  3. Lỗi MySQL 1005?

  4. Tìm kiếm toàn văn bản MySql trong PHP bằng cách sử dụng chuỗi chứa từ khóa

  5. Bash:Làm thế nào để gọi lệnh và lưu trữ kết quả trong một biến?