PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Goroutine memblokir kumpulan koneksi

Apa yang Anda miliki adalah kebuntuan . Dalam skenario terburuk, Anda memiliki 15 goroutine yang memiliki 15 koneksi database, dan ke-15 goroutine tersebut memerlukan koneksi baru untuk melanjutkan. Tetapi untuk mendapatkan koneksi baru, seseorang harus maju dan melepaskan koneksi:deadlock.

Artikel wikipedia tertaut merinci pencegahan kebuntuan. Misalnya, eksekusi kode hanya boleh memasuki bagian kritis (yang mengunci sumber daya) ketika ia memiliki semua sumber daya yang dibutuhkan (atau akan dibutuhkan). Dalam hal ini, ini berarti Anda harus memesan 2 koneksi (tepatnya 2; jika hanya 1 yang tersedia, tinggalkan dan tunggu), dan jika Anda memiliki 2 koneksi itu, baru lanjutkan dengan kueri. Tetapi di Go Anda tidak dapat memesan koneksi terlebih dahulu. Mereka dialokasikan sesuai kebutuhan saat Anda menjalankan kueri.

Umumnya pola ini harus dihindari. Anda tidak boleh menulis kode yang terlebih dahulu mencadangkan sumber daya (terbatas) (dalam hal ini koneksi db), dan sebelum merilisnya, ia meminta sumber daya yang lain.

Solusi mudah adalah dengan mengeksekusi kueri pertama, simpan hasilnya (misalnya ke dalam irisan Go), dan ketika Anda selesai melakukannya, lanjutkan dengan kueri berikutnya (tetapi juga jangan lupa untuk menutup sql.Rows pertama). Dengan cara ini kode Anda tidak memerlukan 2 koneksi secara bersamaan.

Dan jangan lupa untuk menangani kesalahan! Saya menghilangkannya untuk singkatnya, tetapi Anda tidak boleh dalam kode Anda.

Seperti inilah tampilannya:

go func() {
    defer wg.Done()

    rows, _ := db.Query("SELECT * FROM reviews LIMIT 1")
    var data []int // Use whatever type describes data you query
    for rows.Next() {
        var something int
        rows.Scan(&something)
        data = append(data, something)
    }
    rows.Close()

    for _, v := range data {
        // You may use v as a query parameter if needed
        db.Exec("SELECT * FROM reviews LIMIT 1")
    }
}()

Perhatikan bahwa rows.Close() harus dieksekusi sebagai defer pernyataan untuk memastikan itu akan dieksekusi (bahkan jika terjadi kepanikan). Tetapi jika Anda hanya menggunakan defer rows.Close() , yang hanya akan dieksekusi setelah kueri berikutnya dieksekusi, sehingga tidak akan mencegah kebuntuan. Jadi saya akan refactor untuk memanggilnya di fungsi lain (yang mungkin merupakan fungsi anonim) di mana Anda dapat menggunakan defer :

    rows, _ := db.Query("SELECT * FROM reviews LIMIT 1")
    var data []int // Use whatever type describes data you query
    func() {
        defer rows.Close()
        for rows.Next() {
            var something int
            rows.Scan(&something)
            data = append(data, something)
        }
    }()

Perhatikan juga bahwa di for kedua loop pernyataan yang sudah disiapkan (sql.Stmt ) diakuisisi oleh DB.Prepare() mungkin akan menjadi pilihan yang jauh lebih baik untuk mengeksekusi kueri (berparameter) yang sama beberapa kali.

Opsi lainnya adalah meluncurkan kueri berikutnya di goroutine baru sehingga kueri yang dieksekusi di dalamnya dapat terjadi saat koneksi yang saat ini terkunci dilepaskan (atau koneksi lain apa pun yang dikunci oleh goroutine lain), tetapi kemudian tanpa sinkronisasi eksplisit Anda tidak memiliki kontrol kapan mereka dieksekusi. Ini bisa terlihat seperti ini:

go func() {
    defer wg.Done()

    rows, _ := db.Query("SELECT * FROM reviews LIMIT 1")
    defer rows.Close()
    for rows.Next() {
        var something int
        rows.Scan(&something)
        // Pass something if needed
        go db.Exec("SELECT * FROM reviews LIMIT 1")
    }
}()

Untuk membuat program Anda menunggu goroutine ini juga, gunakan WaitGroup Anda sudah beraksi:

        // Pass something if needed
        wg.Add(1)
        go func() {
            defer wg.Done()
            db.Exec("SELECT * FROM reviews LIMIT 1")
        }()



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Isi baris yang hilang saat menggabungkan beberapa bidang di Postgres

  2. server simpul tidak dapat terhubung ke postgres db

  3. Bagaimana saya bisa mengakses database postgresql dari matlab dengan tanpa kotak alat database matlabs?

  4. Di mana file konfigurasi Postgresql:'postgresql.conf' di Windows?

  5. Cara melakukan upser dengan benar di postgres 9.5