Tôi đã gặp rắc rối với sqlit3 này trong hai ngày qua. Lý do là dự án cần có một phần mềm trung gian như vậy. Phần mềm trung gian đảm nhận vai trò API và chuyển tiếp lưu lượng truy cập. yêu cầu phát hiện. Vì vậy, tôi nghĩ ngay đến việc sử dụng go để triển khai nó. Vì các bài học về dữ liệu, tôi không cân nhắc việc sử dụng cơ sở dữ liệu lớn pg nên đã chọn cơ sở dữ liệu sqlite nhẹ. Chương trình được phát triển nhanh chóng. Sau khi trực tuyến và chạy một số nút, không có ngoại lệ trong việc đọc và ghi dữ liệu. Tuy nhiên, khi dữ liệu thử nghiệm đạt đến một mức nhất định, lỗi cơ sở dữ liệu bị khóa sẽ xuất hiện. Sau khi kiểm tra một số thông tin, ý tưởng chung là SQLite có hỗ trợ đọc đồng thời tốt, nhưng việc viết đồng thời không thân thiện lắm nên tôi đã nghĩ ra cách này.
ps: Một phần code đến từ chatGPT. Phải nói là chatGPT quá ngon.
Khi vận hành cơ sở dữ liệu SQLite3 trong Gorm, do cơ chế khóa ghi của SQLite3 dành cho toàn bộ cơ sở dữ liệu chứ không phải một bảng hoặc hàng duy nhất, nên việc đọc và ghi đồng thời ở mức độ cao có thể dẫn đến tình trạng khóa cơ sở dữ liệu.
Để tránh sự cố thư viện khóa, bạn có thể sử dụng các phương pháp sau:
-
Sử dụng chế độ WAL.
Sử dụng chế độ WAL (Ghi nhật ký ghi trước) của SQLite3 có thể làm giảm đáng kể khả năng khóa cơ sở dữ liệu. Trong chế độ WAL, các thao tác đọc sẽ không chặn các hoạt động ghi và các thao tác ghi sẽ không chặn các hoạt động đọc, do đó có thể đạt được các hoạt động đọc và ghi đồng thời cao.
Bạn có thể sử dụng đoạn mã sau để bật chế độ WAL trong Gorm:
import "gorm.io/driver/sqlite" db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{ DSN: "mode=wal", }) // Các tham số trên The phương thức cài đặt không còn được áp dụng. Phương thức cài đặt mới như sau if Inst, err = gorm.Open(sqlite.Open(dsn), gormConfig err == nil { //); Bật chế độ WAL_ = Inst.Exec("PRAGMA tạp chí_mode=WAL;") //_ = Inst.Exec("PRAGMA tạp chí_size_limit=104857600;") //_ = Inst.Exec("PRAGMA busy_timeout=999999;") }
-
Kiểm soát hợp lý phạm vi công việc.
Khi thực hiện các thao tác đọc và ghi đồng thời cao, bạn cần chú ý đến việc kiểm soát phạm vi giao dịch, thu hẹp phạm vi giao dịch càng nhiều càng tốt và giảm thời gian chiếm dụng của khóa ghi. Ví dụ: khi thực hiện thao tác ghi hàng loạt, mỗi lần ghi có thể được chia thành nhiều giao dịch để giảm thời gian bị khóa ghi.
-
Sử dụng bộ nhớ đệm.
Việc sử dụng bộ đệm có thể làm giảm các thao tác đọc trên cơ sở dữ liệu, từ đó giảm khả năng khóa cơ sở dữ liệu. Chức năng bộ nhớ đệm có thể được triển khai bằng cách sử dụng các thư viện bộ nhớ đệm của bên thứ ba như Redis.
-
Tăng số lượng kết nối cơ sở dữ liệu.
Việc tăng số lượng kết nối cơ sở dữ liệu có thể cải thiện khả năng xử lý đồng thời của cơ sở dữ liệu và giảm khả năng khóa cơ sở dữ liệu. Bạn có thể sử dụng đoạn mã sau trong Gorm để tăng số lượng kết nối cơ sở dữ liệu:
nhập "gorm.io/driver/sqlite" db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) sqlDB, dbError := db.DB() if dbError != nil { return nil, fmt.Errorf("không tạo được sqlDB") } // SetMaxIdleConns Đặt số lượng kết nối tối đa trong nhóm kết nối nhàn rỗi sqlDB.SetMaxIdleConns(10) // SetMaxOpenConns đặt số lượng kết nối cơ sở dữ liệu mở tối đa. sqlDB.SetMaxOpenConns(100)'
Cần lưu ý rằng việc tăng số lượng kết nối cũng sẽ làm tăng tải cho máy chủ nên cần có sự điều chỉnh dựa trên điều kiện thực tế.
Tóm lại, bằng cách áp dụng cơ chế khóa, kiểm soát giao dịch, bộ đệm và cài đặt số kết nối thích hợp, vấn đề khóa cơ sở dữ liệu của cơ sở dữ liệu SQLite3 có thể tránh được một cách hiệu quả.
-
Ví dụ 1:
Sau đây là ví dụ mã hoàn chỉnh để Gorm vận hành cơ sở dữ liệu SQLite3, bao gồm các biện pháp như bật chế độ WAL, kiểm soát phạm vi giao dịch, sử dụng bộ đệm và tăng số lượng kết nối cơ sở dữ liệu để tránh sự cố khóa cơ sở dữ liệu.
import ("gorm.io/driver/sqlite" "gorm.io/gorm" "time") // Xác định kiểu cấu trúc mô hình User struct { ID uint Tên chuỗi Tuổi uint8 CreatedAt time.Time UpdateAt time.Time } // Khởi tạo cơ sở dữ liệu kết nối func InitDB() (*gorm.DB, error) { db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{ // Bật chế độ WAL DSN: "mode=wal", // Tăng số lượng kết nối tối đa lên 100 MaxOpenConns: 100, }) if err != nil { return nil, err } // Đặt kết nối cơ sở dữ liệu tham số nhóm sqlDB , err := db.DB() if err != nil { return nil, err } sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) sqlDB.SetConnMaxLifetime(time.Hour) return db, nil } // Xác định hàm ghi hàng loạt func BatchInsertUsers(db *gorm.DB, user []User) lỗi { // Write 1000 mẩu dữ liệu mỗi lần batchSize := 1000 batchCount := (len(users) + batchSize - 1) / batchSize for i := 0; i < batchCount; i++ { start := i * batchSize end := (i + 1) * batchSize if end > len(users) { end = len(users) } batch := user[start:end] // Kích hoạt giao dịch tx := db.Begin() if err := tx.Error; != nil { return err } if err := tx.Create(&batch).Error; err != nil { tx.Rollback() return err } // Cam kết giao dịch if err := tx.Commit().Error; != nil { return err } } return nil } // Truy vấn thông tin người dùng func GetUsers(db *gorm.DB) ([]User, error) { var user []User // Sử dụng bộ đệm để giảm các thao tác đọc trên cơ sở dữ liệu err := db.Cache(&users).Find(&users).Error if err != nil { return nil, err } return user, nil } // Mã mẫu func main() { // Khởi tạo kết nối cơ sở dữ liệu db, err := InitDB() if err != nil { Panic(err) } defer db.Close() // Chèn dữ liệu theo lô user := []User{} for i := 0; i < 100000; " + string(i), Tuổi: uint8(i % 100), CreatedAt: time.Now(), UpdateAt: time.Now(), } user = chắp thêm(người dùng, người dùng) } err = BatchInsertUsers(db, người dùng) if err != nil { Panic(err) } // Truy vấn dữ liệu người dùng, err = GetUsers(db) if err != nil { Panic(err) } for _, user := phạm vi người dùng { fmt.Println(user) } }
-
Ví dụ 2: Sử dụng chế độ WAL và kiểm soát giao dịch để tránh sự cố khóa thư viện:
nhập gói chính ( "fmt" "gorm.io/driver/sqlite" "gorm.io/gorm" ) gõ Người dùng struct { ID uint Tên chuỗi } func main() { // Tạo kết nối cơ sở dữ liệu SQLite3 db, err := gorm .Open(sqlite.Open("test.db"), &gorm.Config{ // Bật chế độ WAL DSN: "mode=wal", }) nếu có lỗi != nil { Panic("không thể kết nối cơ sở dữ liệu") } // Đặt kích thước nhóm kết nối sqlDB, err := db.DB() if err != nil { Panic("không thể đặt kích thước nhóm cơ sở dữ liệu") } sqlDB SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) // Tự động di chuyển bảng tương ứng với mô hình Người dùng err = . db.AutoMigrate(&User{}) if err != nil { hoảng loạn("không thể di chuyển bảng") } // Viết 1000 mẩu dữ liệu đồng thời cho i := 0; { err := db.Transaction(func(tx *gorm.DB) lỗi { user := User{Name: fmt.Sprintf("user_%d", i)} result := tx.Create(&user) return result.Error }) if err != nil { fmt.Printf("không ghi được dữ liệu: %v\n", err) } }(i) } // Đọc đồng thời dữ liệu cho i := 0; i < 1000; i++ { go func() { var user [] Lỗi người dùng := db.Transaction(func(tx *gorm.DB) error { result := tx.Find(&users) return result.Error }) if err != nil { fmt.Printf("không đọc được dữ liệu : %v\n", err) } else { fmt.Printf("đọc %d bản ghi\n", len(users)) } }() } // Đợi 10 giây để tất cả quá trình ghi và đọc hoàn tất time.Sleep(10 * time.Second) }
Trong ví dụ về mã này, trước tiên chúng tôi tạo kết nối cơ sở dữ liệu SQLite3 bằng hàm gorm.Open và đặt kích thước nhóm kết nối cũng như chế độ WAL. Sau đó, chúng ta sử dụng hàm d b.AutoMigrate để tự động di chuyển bảng tương ứng với mô hình Người dùng.
Tiếp theo, chúng tôi ghi đồng thời 1000 mẩu dữ liệu vào vòng lặp và sử dụng kiểm soát giao dịch để kiểm soát phạm vi giao dịch. Mỗi thao tác ghi sẽ tạo một đối tượng Người dùng và ghi nó vào cơ sở dữ liệu bằng hàm tx.Create.
Sau đó, chúng tôi đọc dữ liệu đồng thời trong một vòng lặp khác và sử dụng kiểm soát giao dịch để kiểm soát phạm vi giao dịch. Mỗi thao tác đọc sử dụng hàm tx.Find để đọc tất cả các bản ghi Người dùng từ cơ sở dữ liệu và in ra số lượng bản ghi đã đọc.
Cuối cùng chúng ta đợi 10 giây để mọi thao tác ghi, đọc hoàn tất. Trong ví dụ này, chúng tôi sử dụng việc ghi và đọc đồng thời.
Cuối cùng, bài viết này nói về gorm vận hành sqlite3. Làm thế nào để tránh khóa thư viện có khả năng đọc và ghi đồng thời cao? Bài viết này chỉ vậy thôi. Nếu bạn muốn biết thêm về các hoạt động gorm trên sqlite3, làm cách nào để việc đọc và ghi đồng thời cao tránh bị khóa thư viện? Về nội dung, vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!