MySQL nhận giá trị duy nhất tiếp theo mà không cần tăng tự động


7

Tôi có một cơ sở dữ liệu MySQL (InnoDB) mà tôi đang phát triển để theo dõi Đơn đặt hàng làm việc tại tổ chức của mình. Có nhiều 'trang web và mỗi trang web có số thứ tự công việc bắt đầu từ 100.

WorkorderID    SiteID    SiteWorkorderNum
     1           1            100
     2           1            101
     3           2            100

WorkorderID là trường tăng tự động.
SiteIDSiteWorkorderNum đều được đặt làm một ràng buộc duy nhất.

Bất cứ khi nào một đơn đặt hàng công việc mới sắp được chèn cho một trang web cụ thể, ứng dụng sẽ kiểm tra tối đa (SiteWorkorderNum) cho trang web của bất kỳ ai đã đăng nhập và trả về giá trị đó cho câu lệnh chèn. Vấn đề tôi muốn tránh là nếu cả hai người dùng của cùng một trang đều nhập một đơn đặt hàng công việc mới cùng một lúc.

Tôi có một vài giải pháp khả thi nhưng tôi muốn xem liệu có cách nào tốt hơn vì mỗi cách đều có nhược điểm, nhưng tôi chắc chắn sẽ tốt hơn các giải pháp khác, và tất nhiên tôi mở ra cho những ý tưởng mới.

1) Khóa bảng để đảm bảo không có người dùng nào khác truy xuất giá trị SiteWorkorderNum cho đến khi chúng tôi đã truy xuất và chèn các giá trị của chúng tôi (tuy nhiên, giả sử chúng tôi có hàng ngàn người dùng cố gắng nhập đơn hàng công việc mỗi phút, liệu bảng có bị khóa không? )

2) Không khóa bảng và truy xuất SiteWorkorderNum tiếp theo và thử chèn vào cơ sở dữ liệu, nếu tôi nhận được một lỗi ràng buộc duy nhất, hãy bắt lỗi và thử lại cho đến khi tôi thành công. (điều này có thể giữ cho bảng được giải phóng, nhưng một lần nữa giả vờ rằng chúng ta có hàng ngàn người dùng trên cùng một trang, liệu nhiều cuộc gọi cơ sở dữ liệu có hơi kém hiệu quả không?)

Tôi có quá hoang tưởng về cách một trong hai giải pháp này 'có thể' thực hiện hiệu quả không? Tất nhiên tôi không có hàng ngàn người dùng, nhưng tôi muốn áp dụng thực tiễn tốt nhất trong thiết kế này trong trường hợp tôi từng làm việc trong một dự án có lưu lượng truy cập cao.


Sẽ có một giải pháp đơn giản nếu bạn đang sử dụng MyISAM.
ypercubeᵀᴹ

Câu trả lời:


2

Điều thú vị về tình huống này có thể được giải quyết bằng cách sử dụng bộ lưu trữ MyISAM.

Tôi đã trả lời một câu hỏi như thế này vào tháng 4 năm 2012: Làm thế nào bạn có thể có hai cột tăng tự động trong một bảng? Bạn cần tạo một bảng với mục đích duy nhất là tạo các chuỗi thứ tự công việc cho mỗi trang

CREATE TABLE site_workorder_seq
(
    SiteID int not null,
    SiteWorkorderNum int not null auto_increment,
    PRIMARY KEY (SiteID,SiteWorkorderNum)
) ENGINE=MyISAM;

Dưới đây là một mẫu tải vào bảng này:

mysql>     DROP DATABASE david;
Query OK, 1 row affected (0.01 sec)

mysql>     CREATE DATABASE david;
Query OK, 1 row affected (0.00 sec)

mysql>     USE david
Database changed
mysql>     CREATE TABLE site_workorder_seq
    ->     (
    ->         SiteID int not null,
    ->         SiteWorkorderNum int not null auto_increment,
    ->         PRIMARY KEY (SiteID,SiteWorkorderNum)
    ->     ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)

mysql>     INSERT INTO site_workorder_seq (SiteID) VALUES
    ->     (1),(1),(2),(3),(3),(3),(3),(4),(4),(4),
    ->     (5),(5),(4),(2),(2),(2);
Query OK, 16 rows affected (0.00 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql>     SELECT * FROM site_workorder_seq;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                1 |
|      1 |                2 |
|      2 |                1 |
|      2 |                2 |
|      2 |                3 |
|      2 |                4 |
|      3 |                1 |
|      3 |                2 |
|      3 |                3 |
|      3 |                4 |
|      4 |                1 |
|      4 |                2 |
|      4 |                3 |
|      4 |                4 |
|      5 |                1 |
|      5 |                2 |
+--------+------------------+
16 rows in set (0.00 sec)

mysql>

Hãy xem WorkorderNum cuối cùng từ mỗi trang web

mysql> SELECT SiteID,MAX(SiteWorkorderNum) SiteWorkorderNum
    -> FROM site_workorder_seq GROUP BY SiteID;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                2 |
|      2 |                4 |
|      3 |                4 |
|      4 |                4 |
|      5 |                2 |
+--------+------------------+
5 rows in set (0.05 sec)

mysql>

Bây giờ, giả sử bạn muốn nhận SiteWorkorderNum tiếp theo cho SiteID 3. Bạn có thể làm điều này:

INSERT INTO site_workorder_seq (SiteID) VALUES (3);
SELECT MAX(SiteWorkorderNum) INTO @nextworkordernum
FROM site_workorder_seq WHERE SiteID=3;
SELECT @nextworkordernum;

Hãy chạy cái này và xem điều gì sẽ xảy ra

mysql> INSERT INTO site_workorder_seq (SiteID) VALUES (3);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT MAX(SiteWorkorderNum) INTO @nextworkordernum
    -> FROM site_workorder_seq WHERE SiteID=3;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT @nextworkordernum;
+-------------------+
| @nextworkordernum |
+-------------------+
|                 5 |
+-------------------+
1 row in set (0.03 sec)

mysql> SELECT * FROM site_workorder_seq;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                1 |
|      1 |                2 |
|      2 |                1 |
|      2 |                2 |
|      2 |                3 |
|      2 |                4 |
|      3 |                1 |
|      3 |                2 |
|      3 |                3 |
|      3 |                4 |
|      3 |                5 |
|      4 |                1 |
|      4 |                2 |
|      4 |                3 |
|      4 |                4 |
|      5 |                1 |
|      5 |                2 |
+--------+------------------+
17 rows in set (0.00 sec)

mysql> SELECT SiteID,MAX(SiteWorkorderNum) SiteWorkorderNum
    -> FROM site_workorder_seq GROUP BY SiteID;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                2 |
|      2 |                4 |
|      3 |                5 |
|      4 |                4 |
|      5 |                2 |
+--------+------------------+
5 rows in set (0.00 sec)

mysql>

Miễn là bạn sử dụng một MyISAM này ngoài tất cả các bảng InnoDB, bạn có thể tạo các bảng điều khiển trên mỗi trang cho nội dung trái tim của bạn.


Điều gì xảy ra nếu tôi muốn một cột tăng tự động bổ sung để sử dụng làm khóa chính cho tất cả các đơn đặt hàng công việc? (trong bảng site_workorder_seq). Tôi đoán điều đó là không thể vì tôi đã chỉ định một cột tăng tự động.
dangel

Thêm một câu hỏi nữa (có thể nằm ngoài phạm vi của bài đăng này), vì MyISAM không hỗ trợ giao dịch, nếu tôi bắt đầu giao dịch, hãy chèn vào bảng MyISAM và tiếp tục các hoạt động của mình trên các bảng khác, sẽ chèn vào Bảng MyISAM khiến giao dịch cam kết sớm?
dangel

Rất có thể bạn sẽ cần một bảng khác được điền thông qua trình kích hoạt SAU KHI trên trang web_workorder_seq. Nếu bạn đăng nó như một câu hỏi khác, tôi có thể chụp nó.
RolandoMySQLDBA

Để trả lời câu hỏi khác, có không may.
RolandoMySQLDBA

Cảm ơn bạn đã giúp đỡ! Tôi sẽ nghiên cứu vấn đề này và xem tôi sẽ đi đâu từ đây và tạo một bài đăng mới với bất kỳ câu hỏi mới nào tôi đưa ra.
dangel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.