2012-03-21 60 views
6

Tôi đang giúp một người bạn có biểu mẫu dựa trên web dành cho doanh nghiệp của họ. Tôi đang cố gắng làm cho nó sẵn sàng để xử lý nhiều người dùng. Tôi đã thiết lập nó để ngay trước khi bản ghi được hiển thị để chỉnh sửa Tôi đang khóa bản ghi với mã sau đây.khóa hàng mysql qua php

$query = "START TRANSACTION;"; 
mysql_query($query); 
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;"; 
mysql_query($query); 

(ổn mà là rất đơn giản nhưng đó là bản chất của mysql)

Nó không có vẻ hoạt. Tuy nhiên, khi tôi đi trực tiếp vào mysql từ dòng lệnh, đăng nhập với cùng một người dùng và thực hiện

START TRANSACTION; 
SELECT field FROM table WHERE ID = "40" FOR UPDATE; 

tôi hiệu quả có thể ngăn chặn các hình thức web truy cập kỷ lục "40" và nhận được cảnh báo thời gian chờ.

Tôi đã thử sử dụng BEGIN thay vì BẮT ĐẦU GIAO DỊCH. Tôi đã thử làm SET AUTOCOMMIT = 0 đầu tiên và bắt đầu giao dịch sau khi khóa nhưng tôi dường như không thể khóa hàng từ mã PHP. Kể từ khi tôi có thể khóa hàng từ dòng lệnh tôi không nghĩ rằng có một vấn đề với cách cơ sở dữ liệu được thiết lập. Tôi thực sự hy vọng rằng có một số điều đơn giản mà tôi đã bỏ lỡ trong bài đọc của mình.

FYI, tôi đang phát triển trên phiên bản XAMPP 1.7.3 có Apache 2.2.14, MySQL 5.1.41 và PHP 5.3.1.

Xin cảm ơn trước. Đây là lần đầu tiên tôi đăng bài nhưng tôi đã thu thập rất nhiều kiến ​​thức từ trang web này trong quá khứ.

+0

Bạn đã làm gì sau lần thứ hai mysql_query ($ query); ?nếu thoát tập lệnh php của bạn, sau đó khóa phát hành – PasteBT

Trả lời

0

Sử dụng PDO cho điều này (và tất cả các hoạt động cơ sở dữ liệu):

$value = 40; 

try { 
    $dbh = new PDO("mysql:host=localhost;dbname=dbname", 'username', 'password'); 
} catch (PDOException $e) { 
    die('Could not connect to database.'); 
} 

$dbh->beginTransaction(); 

try { 
    $stm = $dbh->prepare("SELECT field FROM table WHERE ID = ? FOR UPDATE"); 
    $stm->execute(array($value)); 
    $dbh->commit(); 
} catch (PDOException $e) { 
    $dbh->rollBack(); 
} 

Nếu bạn phải sử dụng mysql_ cổ * chức năng bạn một cái gì đó như thể:

mysql_query('SET AUTOCOMMIT=0'); 
mysql_query('START TRANSACTION'); 
mysql_query($sql); 
mysql_query('SET AUTOCOMMIT=1'); 
+2

Đừng downvote trong im lặng. Để lại một bình luận để giúp câu trả lời tốt hơn. – webbiedave

+2

Đối với hồ sơ tôi thấy không có vấn đề với đề nghị này, nó là suy nghĩ về phía trước! – Paul

0

Bạn không nên sử dụng api mysql vì nó dễ dàng để làm cho những sai lầm mà cho phép sql-tiêm và như vậy, cũng như nó thiếu một số chức năng. Tôi nghi ngờ rằng giao dịch là một trong những vì nếu tôi không sai mỗi truy vấn được gửi "của chính nó" và không phải trong một bối cảnh lớn hơn.

Tuy nhiên, giải pháp là sử dụng một số api khác, tôi thích mysqli vì nó tương tự như mysql và được hỗ trợ rộng rãi. Bạn có thể dễ dàng viết lại mã của mình để sử dụng mysqli thay thế.

Đối với chức năng giao dịch, hãy đặt tự động cam kết thành sai và tự cam kết khi bạn muốn. Điều này cũng giống như bắt đầu và dừng giao dịch.

Đối với giao diện tài liệu tham khảo tại địa chỉ:

http://www.php.net/manual/en/mysqli.autocommit.php

http://www.php.net/manual/en/mysqli.commit.php

9

Vấn đề không phải là cú pháp của mã của bạn, nhưng cách bạn đang cố gắng sử dụng nó.

ngay trước khi kỷ lục được hiển thị để chỉnh sửa Tôi khóa kỷ lục với đoạn mã sau

Từ đó tôi giả định rằng bạn chọn và "khóa" hàng, sau đó hiển thị mà chỉnh sửa trang để người dùng của bạn, sau đó khi họ gửi các thay đổi mà nó lưu và "mở khóa" bảng. Ở đây nằm trong vấn đề cơ bản. Khi trang của bạn tải xong, PHP thoát và đóng kết nối MySQL. Khi điều này xảy ra, tất cả các khóa được giải phóng ngay lập tức. Đây là lý do tại sao giao diện điều khiển dường như hoạt động khác với PHP của bạn. Tương đương trong giao diện điều khiển sẽ là bạn thoát khỏi chương trình.

Bạn không thể khóa các hàng trong bảng để chỉnh sửa trong một khoảng thời gian dài. Đây không phải là thiết kế của họ. Nếu bạn muốn khóa bản ghi để chỉnh sửa, bạn cần theo dõi các khóa này trong bảng khác. Tạo một bảng mới có tên là "edit_locks" và lưu trữ id bản ghi đang bị khóa, chỉnh sửa id người dùng và thời gian bị khóa. Khi bạn muốn mở một bản ghi để chỉnh sửa, hãy khóa toàn bộ bảng edit_locks và truy vấn để xem liệu bản ghi có bị khóa bởi người khác hay không. Nếu không, hãy lắp bản ghi khóa của bạn, nếu có, sau đó hiển thị lỗi bị khóa. Khi người dùng lưu hoặc hủy, hãy xóa bản ghi khóa khỏi edit_locks. Nếu bạn muốn làm mọi việc dễ dàng, chỉ cần khóa bảng này bất cứ khi nào chương trình của bạn muốn sử dụng nó. Điều này sẽ giúp bạn tránh được tình trạng chạy đua.

Có một trường hợp khác có thể gây ra sự cố. Nếu người dùng mở một bản ghi để chỉnh sửa, sau đó đóng trình duyệt mà không lưu hoặc hủy, khóa chỉnh sửa sẽ chỉ ở đó mãi mãi. Đây là lý do tại sao tôi nói lưu trữ thời gian nó đã bị khóa. Các biên tập viên chính nó nên thực hiện một cuộc gọi AJAX mỗi 2 phút hoặc lâu hơn để nói "Tôi vẫn cần khóa!". Khi chương trình PHP nhận được yêu cầu "relock" này, nó sẽ tìm kiếm khóa, sau đó cập nhật dấu thời gian cho hiện tại. Bằng cách này, dấu thời gian trên khóa luôn được cập nhật trong vòng 2 phút. Bạn cũng cần phải tạo một chương trình khác để loại bỏ các khóa cũ cũ. Điều này sẽ chạy trong một công việc cron cứ sau vài phút. Nó sẽ tìm kiếm bất kỳ khóa nào có dấu thời gian cũ hơn 5 phút hoặc lâu hơn và xóa. Nếu dấu thời gian cũ hơn, thì rõ ràng trình chỉnh sửa đã đóng một số cách hoặc dấu thời gian sẽ được cập nhật trong vòng 2 phút.

Giống như một số người khác đã đề cập, bạn nên cố gắng sử dụng mysqli. Nó là viết tắt của "MySQL Improved" và là sự thay thế cho giao diện cũ.

+0

Cách làm này có một số ưu điểm nhưng cũng có một số nhược điểm. Bạn sẽ cần một dọn dẹp cho bàn khóa/mở khóa của bạn theo thời gian. Điều này là do sự cố hoặc gián đoạn bất ngờ. Cá nhân tôi sẽ không sử dụng nó. – Andreas

+0

Okay JMack, bạn đã mở rộng câu trả lời ngay bây giờ và giải thích những bất lợi trong phần thứ hai của bạn. Câu trả lời chắc chắn +1 – Andreas

+0

@Andreas Được bao gồm trong mô tả của tôi là một phương pháp để dọn dẹp bàn khóa để bất kỳ sự cố nào của trình duyệt sẽ gây ra việc khóa bản ghi không quá một vài phút. –

0

Đây là một cuộc thảo luận cũ, nhưng có lẽ mọi người vẫn đang theo dõi nó. Tôi sử dụng một phương pháp tương tự như của JMack nhưng bao gồm các thông tin khóa trong bảng tôi muốn row-lock. Các cột mới của tôi là LockTime và LockedBy. Để cố gắng một khóa, tôi làm:

UPDATE table 
SET LockTime='$now',LockedBy='$Userid' 
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid') 

($ qua là 4 phút trước)

Nếu thất bại, người khác có khóa. Tôi có thể mở khóa rõ ràng như sau hoặc để khóa của tôi hết hạn:

UPDATE table 
SET LockTime=NULL,LockedBy='' 
WHERE Key='$value' AND LockedBy='$Userid' 

Công việc cron có thể xóa khóa cũ nhưng không thực sự cần thiết.

Các vấn đề liên quan