


Pertanyaan yang merangkumi Sqlc untuk melaksanakan operasi transaksi yang lebih mudah
Apakah itu SQLC
SQLC ialah alat pembangunan yang berkuasa yang fungsi terasnya adalah untuk menukar pertanyaan SQL kepada kod Go selamat jenis. Dengan menghuraikan pernyataan SQL dan menganalisis struktur pangkalan data, sqlc secara automatik boleh menjana struktur dan fungsi Go yang sepadan, dengan sangat memudahkan proses penulisan kod untuk operasi pangkalan data.
Menggunakan sqlc, pembangun boleh menumpukan pada menulis pertanyaan SQL dan membiarkan penjanaan kod Go yang membosankan berfungsi kepada alat, dengan itu mempercepatkan proses pembangunan dan meningkatkan kualiti kod.
Pelaksanaan transaksi SQLC
Kod yang dijana oleh Sqlc biasanya mengandungi struktur Pertanyaan, yang merangkumi semua operasi pangkalan data. Struktur ini melaksanakan antara muka Querier umum, yang mentakrifkan semua kaedah pertanyaan pangkalan data.
Kuncinya ialah fungsi Baharu yang dijana oleh sqlc boleh menerima sebarang objek yang melaksanakan antara muka DBTX, termasuk *sql.DB dan *sql.Tx.
Inti pelaksanaan transaksi adalah untuk menggunakan polimorfisme antara muka Go. Apabila anda perlu melakukan operasi dalam urus niaga, anda mencipta objek *sql.Tx dan kemudian menyerahkannya kepada fungsi Baharu untuk mencipta contoh Pertanyaan baharu. Kejadian ini akan melaksanakan semua operasi dalam konteks transaksi.
Andaikan kami menyambung ke pangkalan data Postgres melalui pgx dan memulakan Pertanyaan dengan kod berikut.
var Pool *pgxpool.Pool var Queries *sqlc.Queries func init() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() connConfig, err := pgxpool.ParseConfig("postgres://user:password@127.0.0.1:5432/db?sslmode=disable") if err != nil { panic(err) } pool, err := pgxpool.NewWithConfig(ctx, connConfig) if err != nil { panic(err) } if err := pool.Ping(ctx); err != nil { panic(err) } Pool = pool Queries = sqlc.New(pool) }
Enkapsulasi urus niaga
Kod berikut ialah enkapsulasi transaksi sqlc yang bijak, yang memudahkan proses menggunakan transaksi pangkalan data dalam Go. Fungsi ini menerima konteks dan fungsi panggil balik sebagai parameter Fungsi panggil balik ini ialah operasi khusus yang ingin dilakukan oleh pengguna dalam transaksi.
func WithTransaction(ctx context.Context, callback func(qtx *sqlc.Queries) (err error)) (err error) { tx, err := Pool.Begin(ctx) if err != nil { return err } defer func() { if e := tx.Rollback(ctx); e != nil && !errors.Is(e, pgx.ErrTxClosed) { err = e } }() if err := callback(Queries.WithTx(tx)); err != nil { return err } return tx.Commit(ctx) }
Fungsi ini mula-mula memulakan urus niaga baharu dan kemudian menangguhkan pelaksanaan untuk memastikan urus niaga itu akhirnya akan ditarik balik melainkan ia dilakukan secara eksplisit. Ini adalah mekanisme keselamatan untuk mengelakkan transaksi yang belum selesai daripada menduduki sumber. Seterusnya, fungsi memanggil panggilan balik yang dibekalkan pengguna, menghantar objek pertanyaan dengan konteks transaksi, membolehkan pengguna melaksanakan operasi pangkalan data yang diperlukan dalam transaksi.
Jika panggilan balik berjaya dilaksanakan tanpa ralat, fungsi melakukan transaksi. Sebarang ralat yang berlaku semasa proses akan menyebabkan transaksi ditarik balik. Kaedah ini bukan sahaja memastikan ketekalan data, tetapi juga sangat memudahkan pengendalian ralat.
Keanggunan enkapsulasi ini ialah ia menyembunyikan logik pengurusan transaksi yang kompleks di sebalik panggilan fungsi yang ringkas. Pengguna boleh menumpukan pada menulis logik perniagaan tanpa perlu risau tentang memulakan, melakukan atau membatalkan urus niaga.
Penggunaan kod ini agak intuitif. Anda boleh memanggil fungsi db.WithTransaction di mana anda perlu melakukan transaksi, menghantar fungsi sebagai parameter yang mentakrifkan semua operasi pangkalan data yang anda ingin lakukan dalam transaksi.
err := db.WithTransaction(ctx, func(qtx *sqlc.Queries) error { // 在这里执行你的数据库操作 // 例如: _, err := qtx.CreateUser(ctx, sqlc.CreateUserParams{ Name: "Alice", Email: "alice@example.com", }) if err != nil { return err } _, err = qtx.CreatePost(ctx, sqlc.CreatePostParams{ Title: "First Post", Content: "Hello, World!", AuthorID: newUserID, }) if err != nil { return err } // 如果所有操作都成功,返回 nil return nil }) if err != nil { // 处理错误 log.Printf("transaction failed: %v", err) } else { log.Println("transaction completed successfully") }
Dalam contoh ini, kami mencipta pengguna dan siaran dalam transaksi. Jika mana-mana operasi gagal, keseluruhan transaksi akan ditarik balik. Jika semua operasi berjaya, transaksi dilakukan.
Faedah pendekatan ini ialah anda tidak perlu mengurus secara manual permulaan, komit atau rollback transaksi, semua ini dikendalikan oleh fungsi db.WithTransaction. Anda hanya perlu menumpukan pada operasi pangkalan data sebenar yang dilakukan dalam transaksi. Ini sangat memudahkan kod dan mengurangkan kemungkinan ralat.
Pembungkusan lanjut
Kaedah pembungkusan yang dinyatakan di atas bukan tanpa kekurangannya.
Pengenkapsulan transaksi mudah ini mempunyai had apabila berurusan dengan transaksi bersarang. Ini kerana ia mencipta transaksi baharu setiap kali dan bukannya menyemak sama ada anda sudah berada dalam satu transaksi.
Untuk melaksanakan pemprosesan transaksi bersarang, kita mesti mendapatkan objek transaksi semasa, tetapi objek transaksi semasa tersembunyi di dalam sqlc.Queries, jadi kita mesti melanjutkan sqlc.Queries.
Struktur yang memanjangkan sqlc.Queries dicipta oleh kami sebagai Repositori Ia memanjangkan *sqlc.Queries dan menambah kumpulan atribut baharu, yang merupakan penunjuk jenis pgxpool.Pool.
type Repositories struct { *sqlc.Queries pool *pgxpool.Pool } func NewRepositories(pool *pgxpool.Pool) *Repositories { return &Repositories{ pool: pool, Queries: sqlc.New(pool), } }
Tetapi apabila kami mula menulis kod, kami akan mendapati bahawa *pgxpool.Pool tidak memenuhi antara muka pgx.Tx Ini kerana *pgxpool.Pool tidak mempunyai kaedah Rollback dan Commit. Ia hanya mengandungi Mula untuk memulakan transaksi. Kaedah, untuk menyelesaikan masalah ini, kami terus meluaskan Repositori, menambah atribut tx baharu padanya dan menambah kaedah NewRepositoriesTx baharu padanya.
type Repositories struct { *sqlc.Queries tx pgx.Tx pool *pgxpool.Pool } func NewRepositoriesTx(tx pgx.Tx) *Repositories { return &Repositories{ tx: tx, Queries: sqlc.New(tx), } }
Sekarang, terdapat kedua-dua atribut pool dan tx dalam struktur Repositori kami. Ini mungkin tidak kelihatan sangat elegan Mengapa kita tidak boleh mengabstrak jenis TX bersatu Terdapat hanya kaedah untuk memulakan transaksi, tetapi bukan kaedah untuk menamatkan transaksi Satu cara untuk menyelesaikan masalah ini ialah dengan mencipta struktur RepositoriesTX lain dan menyimpan pgx.Tx di dalamnya dan bukannya *pgxpool.Pool, tetapi ini mungkin menyebabkan There. adalah soalan baharu. Salah satu daripadanya ialah kita mungkin perlu melaksanakan kaedah WithTransaction untuk kedua-duanya.
func (r *Repositories) WithTransaction(ctx context.Context, fn func(qtx *Repositories) (err error)) (err error) { var tx pgx.Tx if r.tx != nil { tx, err = r.tx.Begin(ctx) } else { tx, err = r.pool.Begin(ctx) } if err != nil { return err } defer func() { if e := tx.Rollback(ctx); e != nil && !errors.Is(e, pgx.ErrTxClosed) { err = e } }() if err := fn(NewRepositoriesTx(tx)); err != nil { return err } return tx.Commit(ctx) }
这个方法和上一章节实现的 WithTransaction 主要不同是,他是实现在 *Repositories 上面而不是全局的,这样我们就可以通过 (r *Repositories) 中的 pgx.Tx 来开始嵌套事务了。
在没有开始事务的时候,我们可以调用 repositories.WithTransaction 来开启一个新的事务。
err := db.repositories.WithTransaction(ctx, func(tx *db.Repositories) error { return nil })
多级事务也是没有问题的,非常容易实现。
err := db.repositories.WithTransaction(ctx, func(tx *db.Repositories) error { // 假设此处进行了一些数据操作 // 然后,开启一个嵌套事务 return tx.WithTransaction(ctx, func(tx *db.Repositories) error { // 这里可以在嵌套事务中进行一些操作 return nil }) })
这个封装方案有效地确保了操作的原子性,即使其中任何一个操作失败,整个事务也会被回滚,从而保障了数据的一致性。
结束语
本文介绍了一个使用 Go 和 pgx 库封装 SQLC 数据库事务的方案。
核心是 Repositories 结构体,它封装了 SQLC 查询接口和事务处理逻辑。通过 WithTransaction 方法,我们可以在现有事务上开始新的子事务或在连接池中开始新的事务,并确保在函数返回时回滚事务。
构造函数 NewRepositories 和 NewRepositoriesTx 分别用于创建普通和事务内的 Repositories 实例。
这样可以将多个数据库操作封装在一个事务中,如果任何一个操作失败,事务将被回滚,提高了代码的可维护性和可读性。
Atas ialah kandungan terperinci Pertanyaan yang merangkumi Sqlc untuk melaksanakan operasi transaksi yang lebih mudah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











Golang lebih baik daripada Python dari segi prestasi dan skalabiliti. 1) Ciri-ciri jenis kompilasi Golang dan model konkurensi yang cekap menjadikannya berfungsi dengan baik dalam senario konvensional yang tinggi. 2) Python, sebagai bahasa yang ditafsirkan, melaksanakan perlahan -lahan, tetapi dapat mengoptimumkan prestasi melalui alat seperti Cython.

Golang lebih baik daripada C dalam kesesuaian, manakala C lebih baik daripada Golang dalam kelajuan mentah. 1) Golang mencapai kesesuaian yang cekap melalui goroutine dan saluran, yang sesuai untuk mengendalikan sejumlah besar tugas serentak. 2) C Melalui pengoptimuman pengkompil dan perpustakaan standard, ia menyediakan prestasi tinggi yang dekat dengan perkakasan, sesuai untuk aplikasi yang memerlukan pengoptimuman yang melampau.

GoisidealforbeginnersandSuekableforcloudandnetworkservicesduetoitssimplicity, kecekapan, danconcurrencyfeatures.1) installgofromtheofficialwebsiteandverifywith'goversion'.2)

Golang sesuai untuk pembangunan pesat dan senario serentak, dan C sesuai untuk senario di mana prestasi ekstrem dan kawalan peringkat rendah diperlukan. 1) Golang meningkatkan prestasi melalui pengumpulan sampah dan mekanisme konvensional, dan sesuai untuk pembangunan perkhidmatan web yang tinggi. 2) C mencapai prestasi muktamad melalui pengurusan memori manual dan pengoptimuman pengkompil, dan sesuai untuk pembangunan sistem tertanam.

Golang dan Python masing -masing mempunyai kelebihan mereka sendiri: Golang sesuai untuk prestasi tinggi dan pengaturcaraan serentak, sementara Python sesuai untuk sains data dan pembangunan web. Golang terkenal dengan model keserasiannya dan prestasi yang cekap, sementara Python terkenal dengan sintaks ringkas dan ekosistem perpustakaan yang kaya.

Perbezaan prestasi antara Golang dan C terutamanya ditunjukkan dalam pengurusan ingatan, pengoptimuman kompilasi dan kecekapan runtime. 1) Mekanisme pengumpulan sampah Golang adalah mudah tetapi boleh menjejaskan prestasi, 2) Pengurusan memori manual C dan pengoptimuman pengkompil lebih cekap dalam pengkomputeran rekursif.

Golang dan C masing-masing mempunyai kelebihan sendiri dalam pertandingan prestasi: 1) Golang sesuai untuk kesesuaian tinggi dan perkembangan pesat, dan 2) C menyediakan prestasi yang lebih tinggi dan kawalan halus. Pemilihan harus berdasarkan keperluan projek dan tumpukan teknologi pasukan.

Golangisidealforbuildingscalablesystemsduetoitseficiencyandcurrency, whilepythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.golang'sdesignencouragescouragescouragescouragescourageSlean, readablecodeanditsouragescouragescourscean,
