sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Làm thế nào để tôi mở khóa cơ sở dữ liệu để điều này sẽ làm việc?
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Làm thế nào để tôi mở khóa cơ sở dữ liệu để điều này sẽ làm việc?
Câu trả lời:
Trong cửa sổ, bạn có thể thử chương trình này http://www.nirsoft.net/utils/opened_files_view.html để tìm hiểu quy trình đang xử lý tệp db. Hãy thử đóng chương trình đó để mở khóa cơ sở dữ liệu
Trong Linux và macOS, bạn có thể làm một cái gì đó tương tự, ví dụ, nếu tệp bị khóa của bạn là Development.db:
$ fuser Development.db
Lệnh này sẽ hiển thị quá trình khóa tệp:
> phát triển.db: 5430
Chỉ cần giết quá trình ...
giết -9 5430
... Và cơ sở dữ liệu của bạn sẽ được mở khóa.
kill
sẽ ổn, nhưng bạn cần cẩn thận để giết nó đúng cách, và kill -9
có lẽ là sai và / hoặc quá mức cần thiết. Nếu quy trình được treo và sẽ không chết, đôi khi bạn cần kill -9
. Nhưng bạn không muốn đi và giết công việc sản xuất chính chỉ để bạn có thể báo cáo rằng cơ sở dữ liệu không còn bị khóa!
Tôi đã khiến db sqlite của tôi bị khóa bằng cách làm sập một ứng dụng trong khi viết. Đây là cách tôi sửa nó:
echo ".dump" | sqlite old.db | sqlite new.db
Lấy từ: http://random.kakaopor.hu/how-to-repair-an-sqlite-database
sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
Trang DatabaseIsLocked được liệt kê bên dưới không còn khả dụng. Trang Khóa và Đồng thời Tệp mô tả các thay đổi liên quan đến khóa tệp được giới thiệu trong v3 và có thể hữu ích cho các độc giả trong tương lai. https://www.sqlite.org/lockingv3.html
Cơ sở dữ liệu wiki SQLite bị khóa cung cấp một lời giải thích tốt về thông báo lỗi này. Một phần, nói rằng nguồn tranh chấp là nội bộ (với quá trình phát ra lỗi).
Điều mà trang này không giải thích là cách SQLite quyết định rằng một cái gì đó trong quy trình của bạn có khóa và điều kiện nào có thể dẫn đến dương tính giả.
Xóa tập tin -journal nghe có vẻ là một ý tưởng khủng khiếp. Nó ở đó để cho phép sqlite khôi phục cơ sở dữ liệu về trạng thái nhất quán sau một sự cố. Nếu bạn xóa nó trong khi cơ sở dữ liệu ở trạng thái không nhất quán, thì bạn sẽ bị cơ sở dữ liệu bị hỏng. Trích dẫn một trang từ trang web sqlite :
Nếu xảy ra sự cố hoặc mất điện và ghi nhật ký nóng trên đĩa, điều cần thiết là tệp cơ sở dữ liệu gốc và nhật ký nóng vẫn còn trên đĩa với tên gốc cho đến khi tệp cơ sở dữ liệu được mở bởi quy trình SQLite khác và khôi phục . [...]
Chúng tôi nghi ngờ rằng một chế độ thất bại phổ biến để phục hồi SQLite xảy ra như sau: Mất điện xảy ra. Sau khi nguồn được phục hồi, người dùng hoặc quản trị viên hệ thống có ý nghĩa bắt đầu tìm kiếm xung quanh đĩa để tìm hư hỏng. Họ thấy tệp cơ sở dữ liệu của họ có tên là "Quan trọng.data". Tập tin này có lẽ quen thuộc với họ. Nhưng sau vụ tai nạn, cũng có một tạp chí nóng có tên "quan trọng.data-tạp chí". Người dùng sau đó xóa tạp chí nóng, nghĩ rằng họ đang giúp dọn dẹp hệ thống. Chúng tôi biết không có cách nào để ngăn chặn điều này ngoài giáo dục người dùng.
Việc khôi phục được cho là sẽ tự động xảy ra vào lần tiếp theo khi cơ sở dữ liệu được mở, nhưng nó sẽ thất bại nếu quá trình không thể khóa cơ sở dữ liệu. Như những người khác đã nói, một lý do có thể cho việc này là một quy trình khác hiện đang mở. Một khả năng khác là khóa NFS cũ, nếu cơ sở dữ liệu nằm trên một khối NFS. Trong trường hợp đó, một cách giải quyết là thay thế tệp cơ sở dữ liệu bằng một bản sao mới không bị khóa trên máy chủ NFS (mv database.db original.db; cp original.db database.db). Lưu ý rằng Câu hỏi thường gặp về sqlite khuyến nghị thận trọng về việc truy cập đồng thời vào cơ sở dữ liệu trên các khối lượng NFS, do các lỗi triển khai khóa tệp NFS.
Tôi không thể giải thích lý do tại sao xóa tệp -journal sẽ cho phép bạn khóa cơ sở dữ liệu mà trước đây bạn không thể. Đó có phải là tái sản xuất?
Nhân tiện, sự hiện diện của một tập tin báo cáo không nhất thiết có nghĩa là có một sự cố hoặc có những thay đổi sẽ được khôi phục. Sqlite có một vài chế độ nhật ký khác nhau và trong chế độ PERSIST hoặc TRUNCATE, nó luôn để tệp -journal luôn thay đổi và thay đổi nội dung để cho biết liệu có giao dịch một phần hay không.
Nếu bạn muốn xóa lỗi "cơ sở dữ liệu bị khóa" thì hãy làm theo các bước sau:
Nếu một quá trình có khóa trên SQLite DB và gặp sự cố, DB sẽ bị khóa vĩnh viễn. Đó chính là vấn đề. Không phải là một số quá trình khác có khóa.
các tệp db SQLite chỉ là các tệp, vì vậy bước đầu tiên sẽ là đảm bảo nó không chỉ đọc. Một điều khác cần làm là đảm bảo rằng bạn không có một loại trình xem DB SQLite GUI nào với DB mở. Bạn có thể mở DB trong một shell khác hoặc mã của bạn có thể mở DB. Thông thường bạn sẽ thấy điều này nếu một luồng hoặc ứng dụng khác như Trình duyệt cơ sở dữ liệu SQLite có DB mở để ghi.
Tôi đã gặp vấn đề này ngay bây giờ, bằng cách sử dụng cơ sở dữ liệu SQLite trên máy chủ từ xa, được lưu trữ trên ngàm NFS. SQLite không thể có được khóa sau khi phiên shell từ xa mà tôi sử dụng bị hỏng trong khi cơ sở dữ liệu đang mở.
Các công thức phục hồi được đề xuất ở trên không phù hợp với tôi (bao gồm cả ý tưởng di chuyển đầu tiên và sau đó sao chép lại cơ sở dữ liệu). Nhưng sau khi sao chép nó vào một hệ thống không phải NFS, cơ sở dữ liệu đã có thể sử dụng được và không có dữ liệu nào bị mất.
Khóa của tôi là do hệ thống bị sập chứ không phải do quá trình treo. Để giải quyết vấn đề này, tôi chỉ cần đổi tên tệp sau đó sao chép lại tên và vị trí ban đầu của nó.
Sử dụng shell linux sẽ là ...
mv mydata.db temp.db
cp temp.db mydata.db
Tôi đã thêm " Pooling=true
" vào chuỗi kết nối và nó hoạt động.
Tôi thấy tài liệu về các trạng thái khóa khác nhau trong SQLite rất hữu ích. Michael, nếu bạn có thể thực hiện đọc nhưng không thể thực hiện ghi vào cơ sở dữ liệu, điều đó có nghĩa là một quy trình đã nhận được khóa RESERVED trên cơ sở dữ liệu của bạn nhưng chưa thực hiện ghi. Nếu bạn đang sử dụng SQLite3, có một khóa mới gọi là PENDING trong đó không có quá trình nào được phép kết nối nhưng các kết nối hiện tại có thể thực hiện đọc, vì vậy nếu đây là vấn đề bạn nên xem xét thay thế.
Tôi gặp vấn đề như vậy trong ứng dụng, có quyền truy cập vào SQLite từ 2 kết nối - một là chỉ đọc và thứ hai để viết và đọc. Có vẻ như kết nối chỉ đọc bị chặn viết từ kết nối thứ hai. Cuối cùng, hóa ra là cần phải hoàn thiện hoặc, ít nhất, thiết lập lại các tuyên bố đã chuẩn bị NGAY LẬP TỨC sau khi sử dụng. Cho đến khi tuyên bố chuẩn bị được mở, nó gây ra cơ sở dữ liệu đã bị chặn để viết.
ĐỪNG BỎ QUA GỌI:
sqlite_reset(xxx);
hoặc là
sqlite_finalize(xxx);
Một số chức năng, như INDEX, có thể mất nhiều thời gian - và nó khóa toàn bộ cơ sở dữ liệu trong khi nó chạy. Trong trường hợp như vậy, nó thậm chí có thể không sử dụng tệp nhật ký!
Vì vậy, cách tốt nhất / duy nhất để kiểm tra xem cơ sở dữ liệu của bạn có bị khóa hay không bởi vì một quá trình HOẠT ĐỘNG ghi vào nó (và do đó bạn nên để nó một mình cho đến khi hoàn thành hoạt động của nó) là md5 (hoặc md5sum trên một số hệ thống) tệp hai lần . Nếu bạn nhận được một tổng kiểm tra khác, cơ sở dữ liệu đang được viết và bạn thực sự thực sự không muốn giết -9 quá trình đó bởi vì bạn có thể dễ dàng kết thúc với một bảng / cơ sở dữ liệu bị hỏng nếu bạn làm như vậy.
Tôi sẽ nhắc lại, bởi vì nó quan trọng - giải pháp KHÔNG phải là tìm chương trình khóa và giết nó - đó là tìm xem cơ sở dữ liệu có khóa ghi vì lý do chính đáng hay không và đi từ đó. Đôi khi giải pháp chính xác chỉ là một tách cà phê.
Cách duy nhất để tạo ra tình huống bị khóa nhưng không được viết này là nếu chương trình của bạn chạy BEGIN EXCLUSIVE
, bởi vì nó muốn thực hiện một số thay đổi bảng hoặc một cái gì đó, sau đó vì bất kỳ lý do gì không bao giờ gửi END
sau đó và quá trình không bao giờ kết thúc . Tất cả ba điều kiện được đáp ứng là rất khó xảy ra trong bất kỳ mã được viết chính xác nào và như vậy trong 99 lần khi ai đó muốn giết -9 quá trình khóa của họ, quá trình khóa thực sự khóa cơ sở dữ liệu của bạn vì một lý do chính đáng. Các lập trình viên thường không thêm BEGIN EXCLUSIVE
điều kiện trừ khi họ thực sự cần, bởi vì nó ngăn chặn sự tương tranh và làm tăng khiếu nại của người dùng. Bản thân SQLite chỉ thêm nó khi nó thực sự cần (như khi lập chỉ mục).
Cuối cùng, trạng thái 'bị khóa' không tồn tại bên trong tệp như một số câu trả lời đã nêu - nó nằm trong nhân của Hệ điều hành. Quá trình đã chạy BEGIN EXCLUSIVE
đã yêu cầu từ HĐH một khóa được đặt trên tệp. Ngay cả khi quy trình độc quyền của bạn bị hỏng, hệ điều hành của bạn sẽ có thể tìm ra liệu nó có duy trì khóa tệp hay không !! Không thể kết thúc với một cơ sở dữ liệu bị khóa nhưng không có quá trình nào chủ động khóa nó !! Khi xem quá trình nào đang khóa tệp, tốt hơn hết là sử dụng lsof thay vì fuser (đây là một minh chứng tốt về lý do: /unix/94316/fuser-vs-lsof- để kiểm tra các tập tin đang sử dụng ). Ngoài ra, nếu bạn có DTrace (OSX), bạn có thể sử dụng iosnoop trên tệp.
Tôi vừa có một điều tương tự xảy ra với tôi - ứng dụng web của tôi có thể đọc từ cơ sở dữ liệu, nhưng không thể thực hiện bất kỳ chèn hoặc cập nhật nào. Việc khởi động lại Apache đã giải quyết vấn đề ít nhất là tạm thời.
Tuy nhiên, thật tuyệt khi có thể theo dõi nguyên nhân gốc rễ.
Liên kết này giải quyết vấn đề. : Khi Sqlite đưa ra: Lỗi khóa cơ sở dữ liệu Nó đã giải quyết vấn đề của tôi có thể hữu ích cho bạn.
Và bạn có thể sử dụng giao dịch bắt đầu và kết thúc giao dịch để không khiến cơ sở dữ liệu bị khóa trong tương lai.
Phải là vấn đề nội bộ của cơ sở dữ liệu ...
Đối với tôi, nó đã được biểu hiện sau khi thử duyệt cơ sở dữ liệu bằng "Trình quản lý SQLite" ...
Vì vậy, nếu bạn không thể tìm thấy một quy trình khác kết nối với cơ sở dữ liệu và bạn không thể sửa nó, chỉ cần thử giải pháp triệt để này:
rake db:migrate
"Tôi gặp vấn đề tương tự trên Mac OS X 10.5.7 khi chạy các tập lệnh Python từ phiên cuối. Mặc dù tôi đã dừng các tập lệnh và cửa sổ đầu cuối đang ngồi ở dấu nhắc lệnh, nó sẽ báo lỗi này vào lần chạy tiếp theo. Giải pháp là đóng cửa sổ terminal và sau đó mở lại. Không có ý nghĩa với tôi, nhưng nó đã làm việc.
Tôi đã từng gặp vấn đề tương tự. Rõ ràng hàm rollback dường như ghi đè lên tệp db với nhật ký giống như tệp db nhưng không có thay đổi gần đây nhất. Tôi đã thực hiện điều này trong mã của mình bên dưới và nó đã hoạt động tốt kể từ đó, trong khi trước đó mã của tôi sẽ bị kẹt trong vòng lặp khi cơ sở dữ liệu bị khóa.
Hi vọng điêu nay co ich
##############
#### Defs ####
##############
def conn_exec( connection , cursor , cmd_str ):
done = False
try_count = 0.0
while not done:
try:
cursor.execute( cmd_str )
done = True
except sqlite.IntegrityError:
# Ignore this error because it means the item already exists in the database
done = True
except Exception, error:
if try_count%60.0 == 0.0: # print error every minute
print "\t" , "Error executing command" , cmd_str
print "Message:" , error
if try_count%120.0 == 0.0: # if waited for 2 miutes, roll back
print "Forcing Unlock"
connection.rollback()
time.sleep(0.05)
try_count += 0.05
def conn_comit( connection ):
done = False
try_count = 0.0
while not done:
try:
connection.commit()
done = True
except sqlite.IntegrityError:
# Ignore this error because it means the item already exists in the database
done = True
except Exception, error:
if try_count%60.0 == 0.0: # print error every minute
print "\t" , "Error executing command" , cmd_str
print "Message:" , error
if try_count%120.0 == 0.0: # if waited for 2 miutes, roll back
print "Forcing Unlock"
connection.rollback()
time.sleep(0.05)
try_count += 0.05
##################
#### Run Code ####
##################
connection = sqlite.connect( db_path )
cursor = connection.cursor()
# Create tables if database does not exist
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS fix (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS tx (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS completed (fix DATE, tx DATE);''')
conn_comit( connection )
Một lý do phổ biến để có ngoại lệ này là khi bạn đang cố thực hiện thao tác ghi trong khi vẫn giữ tài nguyên cho thao tác đọc. Ví dụ: nếu bạn CHỌN từ một bảng, sau đó thử CẬP NHẬT thứ gì đó bạn đã chọn mà không đóng Kết quả của bạn trước.
Tôi cũng gặp lỗi "cơ sở dữ liệu bị khóa" trong một ứng dụng đa luồng, dường như là mã kết quả SQLITE_BUSY và tôi đã giải quyết nó bằng cách đặt sqlite3_busy_timeout thành thứ gì đó phù hợp như 30000.
(Một lưu ý phụ, thật kỳ lạ khi câu hỏi 7 năm chưa ai tìm ra điều này! SQLite thực sự là một dự án kỳ lạ và tuyệt vời ...)
Trước khi đi xuống tùy chọn khởi động lại, đáng để xem liệu bạn có thể tìm thấy người dùng cơ sở dữ liệu sqlite hay không.
Trên Linux, người ta có thể sử dụng fuser
đến cuối này:
$ fuser database.db
$ fuser database.db-journal
Trong trường hợp của tôi, tôi đã nhận được phản hồi như sau:
philip 3556 4700 0 10:24 pts/3 00:00:01 /usr/bin/python manage.py shell
Điều đó cho thấy rằng tôi đã có một chương trình Python khác với pid 3556 (Manage.py) bằng cơ sở dữ liệu.
Một câu hỏi cũ, với rất nhiều câu trả lời, đây là các bước tôi đã theo dõi gần đây để đọc các câu trả lời ở trên, nhưng trong trường hợp của tôi, vấn đề là do chia sẻ tài nguyên của cifs. Trường hợp này không được báo cáo trước đây, vì vậy hy vọng nó sẽ giúp được ai đó.
Cố gắng ép chế độ khóa khi mở kết nối bằng
final SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(false);
config.setLockingMode(LockingMode.NORMAL);
connection = DriverManager.getConnection(url, config.toProperties());
Nếu bạn sử dụng tệp db SQLite của mình qua thư mục dùng chung NFS, hãy kiểm tra điểm này của faq SQLite và xem lại các tùy chọn cấu hình gắn kết của bạn để đảm bảo tránh các khóa, như được mô tả ở đây :
//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
Tôi đã gặp lỗi này trong một kịch bản hơi khác với các mô tả ở đây.
Cơ sở dữ liệu SQLite nằm trên hệ thống tệp NFS được chia sẻ bởi 3 máy chủ. Trên 2 trong số các máy chủ tôi đã có thể chạy các truy vấn trên cơ sở dữ liệu thành công, trên máy chủ thứ ba nghĩ rằng tôi nhận được thông báo "cơ sở dữ liệu bị khóa".
Điều với chiếc máy thứ 3 này là nó không còn chỗ trống /var
. Mỗi lần tôi cố chạy một truy vấn trong cơ sở dữ liệu BẤT K SQL SQLite nào trong hệ thống tệp này, tôi nhận được thông báo "cơ sở dữ liệu bị khóa" và cũng có lỗi này trên nhật ký:
Ngày 8 tháng 8 10:33:38 kernel01 server: lockd: không thể theo dõi 172.22.84.87
Và cái này cũng vậy:
Ngày 8 tháng 8 10:33:38 server01 rpc.statd [7430]: Không thể chèn: write /var/lib/nfs/statd/sm/other.server.name.com: Không còn chỗ trống trên thiết bị 8 tháng 8 10:33: 38 máy chủ01 rpc.statd [7430]: STAT_FAIL đến máy chủ01 cho SM_MON là 172,22.84.87
Sau khi tình hình không gian được xử lý, mọi thứ trở lại bình thường.
Nếu bạn đang cố mở khóa cơ sở dữ liệu Chrome để xem nó bằng SQLite , thì chỉ cần tắt Chrome.
các cửa sổ
%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Web Data
or
%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Chrome Web Data
Mac
~/Library/Application Support/Google/Chrome/Default/Web Data
Từ những bình luận trước đây của bạn, bạn đã nói rằng một tập tin báo cáo đã có mặt.
Điều này có thể có nghĩa là bạn đã mở và giao dịch (ĐỘC QUYỀN?) Và chưa cam kết dữ liệu. Có phải chương trình của bạn hoặc một số quy trình khác để lại các phóng viên phía sau ??
Khởi động lại quá trình sqlite sẽ xem xét tệp nhật ký và dọn sạch mọi hành động không được cam kết và xóa tệp -journal.
Như Seun Osewa đã nói, đôi khi một quá trình zombie sẽ ngồi trong thiết bị đầu cuối với một khóa bị ngấm nước, ngay cả khi bạn không nghĩ rằng nó có thể. Kịch bản của bạn chạy, gặp sự cố và bạn quay lại dấu nhắc, nhưng có một quá trình zombie xuất hiện ở đâu đó bởi một cuộc gọi thư viện và quá trình đó có khóa.
Đóng thiết bị đầu cuối bạn đang ở (trên OSX) có thể hoạt động. Khởi động lại sẽ hoạt động. Bạn có thể tìm kiếm các quá trình "trăn" (ví dụ) không làm gì cả và giết chúng.
bạn có thể thử điều này: .timeout 100
để đặt thời gian chờ. Tôi không biết điều gì xảy ra trong dòng lệnh nhưng trong C # .Net khi tôi làm điều này: "UPDATE table-name SET column-name = value;"
Tôi nhận được Cơ sở dữ liệu bị khóa nhưng điều này "UPDATE table-name SET column-name = value"
sẽ ổn.
Có vẻ như khi bạn thêm ;, sqlite sẽ tìm kiếm thêm lệnh.