ORM yang harus digunakan dalam GO: GORM, sqlc, Ent, atau Bun?
GORM vs sqlc vs Ent vs Bun ```
Ekosistem Go menawarkan berbagai alat ORM (Object-Relational Mapping) dan perpustakaan database, masing-masing dengan filosofi mereka sendiri. Berikut adalah perbandingan menyeluruh dari empat solusi utama untuk menggunakan PostgreSQL dalam Go: GORM, sqlc, Ent, dan Bun.
Mari kita evaluasi mereka berdasarkan kinerja, pengalaman pengembang, popularitas, dan fitur/ekstensibilitas, dengan contoh kode yang menunjukkan operasi CRUD dasar pada model User
. Pengembang Go tingkat menengah dan lanjutan akan mendapatkan wawasan tentang trade-off dari setiap alat dan mana yang mungkin paling sesuai dengan kebutuhan mereka.
Ringkasan ORM
-
GORM – ORM yang kaya fitur dengan gaya Active Record. GORM memungkinkan Anda mendefinisikan struktur Go sebagai model dan menyediakan API yang luas untuk menginterogasi dan memanipulasi data menggunakan method chaining. GORM sudah ada selama beberapa tahun dan merupakan salah satu ORM Go yang paling banyak digunakan (dengan hampir 39.000 bintang GitHub). Daya tarik GORM adalah fitur yang kuat (migrasi otomatis, penanganan hubungan, loading yang diminta, transaksi, hooks, dan lainnya) yang memungkinkan kode Go yang bersih dengan sedikit SQL mentah. Namun, GORM memperkenalkan pola-pola sendiri dan memiliki overhead runtime karena penggunaan refleksi dan interface, yang dapat memengaruhi kinerja pada operasi besar.
-
sqlc – Bukan ORM tradisional tetapi generator kode SQL. Dengan sqlc, Anda menulis query SQL biasa (dalam file
.sql
), dan alat ini menghasilkan kode Go yang aman secara tipe (fungsi DAO) untuk menjalankan query tersebut. Ini berarti Anda berinteraksi dengan database dengan memanggil fungsi Go yang dihasilkan (misalnya,CreateUser
,GetUser
) dan mendapatkan hasil yang bertipe kuat tanpa harus memindai baris secara manual. sqlc secara efektif memungkinkan Anda menggunakan SQL mentah dengan keamanan saat kompilasi – tidak ada lapisan pembangun query atau refleksi runtime. sqlc dengan cepat menjadi populer (~16.000 bintang) karena kesederhanaan dan kinerja: ia menghindari sepenuhnya overhead runtime dengan memanfaatkan SQL yang disiapkan, membuatnya secepat menggunakandatabase/sql
secara langsung. Trade-off-nya adalah Anda harus menulis (dan memelihara) pernyataan SQL untuk query Anda, dan logika query dinamis bisa kurang langsung dibandingkan ORM yang membangun SQL untuk Anda. -
Ent (Entgo) – ORM code-first yang menggunakan pembangkitan kode untuk menciptakan API aman secara tipe untuk model data Anda. Anda mendefinisikan skema Anda dalam Go (menggunakan DSL Ent untuk bidang, edge/hubungan, batasan, dll.), lalu Ent menghasilkan paket Go untuk model dan metode query. Kode yang dihasilkan menggunakan API yang bersifat fluent untuk membangun query, dengan pemeriksaan tipe saat kompilasi yang lengkap. Ent relatif lebih baru (didukung oleh Linux Foundation dan dikembangkan oleh Ariga). Fokusnya adalah pengalaman pengembang dan kebenaran – query dibangun melalui metode yang dapat dikaitkan, bukan string mentah, yang membuatnya lebih mudah dikomposisi dan kurang rentan terhadap kesalahan. Pendekatan Ent menghasilkan query SQL yang sangat dioptimalkan dan bahkan menyimpan hasil query untuk mengurangi perjalanan ulang ke database. Ent dirancang dengan skalabilitas dalam pikiran, sehingga menangani skema dan hubungan yang kompleks secara efisien. Namun, menggunakan Ent menambahkan langkah pembangunan (menjalankan codegen) dan mengikat Anda ke ekosistemnya. Saat ini, Ent mendukung PostgreSQL, MySQL, SQLite (dan dukungan eksperimental untuk database lain), sedangkan GORM mendukung rentang database yang lebih luas (termasuk SQL Server dan ClickHouse).
-
Bun – ORM yang lebih baru dengan pendekatan “SQL-first”. Bun terinspirasi oleh Go
database/sql
dan perpustakaan go-pg yang lebih tua, bertujuan untuk menjadi ringan dan cepat dengan fokus pada fitur PostgreSQL. Sebaliknya dari pola Active Record, Bun menyediakan pembangun query fluent: Anda memulai query dengandb.NewSelect()
/NewInsert()
/ dll., dan membangunnya dengan metode yang sangat mirip dengan SQL (Anda bahkan dapat menyisipkan potongan SQL mentah). Ia memetakan hasil query ke struct Go menggunakan tag struct yang mirip dengan GORM. Bun memprioritaskan eksplisit dan memungkinkan kembali ke SQL mentah dengan mudah ketika diperlukan. Ia tidak menjalankan migrasi secara otomatis untuk Anda (Anda menulis migrasi atau menggunakan paket migrate Bun secara manual), yang beberapa orang anggap sebagai kelebihan untuk kontrol. Bun diperkenalkan karena kemampuannya dalam menangani query kompleks secara elegan dan mendukung tipe PostgreSQL lanjutan (array, JSON, dll.) secara langsung. Dalam praktiknya, Bun memberikan sedikit overhead runtime dibandingkan GORM (tidak ada refleksi berat pada setiap query), yang berarti throughput yang lebih baik dalam skenario beban tinggi. Komunitasnya lebih kecil (~4.000 bintang) dan set fiturnya, meskipun solid, tidak sebesar GORM. Bun mungkin memerlukan sedikit pengetahuan SQL lebih untuk digunakan secara efektif, tetapi memberikan imbalan dalam hal kinerja dan fleksibilitas.
Benchmark Kinerja
Ketika datang ke kinerja (latensi query dan throughput), ada perbedaan signifikan dalam cara alat-alat ini berperilaku, terutama saat beban meningkat. Benchmark terbaru dan pengalaman pengguna menyoroti beberapa poin kunci:
-
GORM: Kenyamanan GORM datang dengan biaya kinerja tertentu. Untuk operasi sederhana atau himpunan hasil kecil, GORM bisa sangat cepat – dalam fakta, satu benchmark menunjukkan GORM memiliki waktu eksekusi tercepat untuk query sangat kecil (misalnya, mengambil 1 atau 10 catatan). Namun, seiring dengan meningkatnya jumlah catatan, overhead GORM menyebabkannya tertinggal secara signifikan. Dalam uji mengambil 15.000 baris, GORM sekitar 2× lebih lambat daripada sqlc atau bahkan raw
database/sql
(59,3 ms untuk GORM vs ~31,7 ms untuk sqlc dan 32,0 ms untuk database/sql dalam skenario tersebut). Desain berbasis refleksi dan abstraksi pembangun query menambahkan latensi, dan GORM mungkin mengeluarkan beberapa query untuk beban kompleks (misalnya, satu query per entitas terkait saat menggunakanPreload
secara default), yang dapat memperbesar penundaan. Secara ringkas: GORM biasanya baik untuk beban kerja moderat, tetapi dalam skenario throughput tinggi atau operasi bulk besar, overheadnya dapat menjadi bottleneck. -
sqlc: Karena panggilan sqlc pada dasarnya adalah SQL yang ditulis secara manual, kinerjanya sejajar dengan menggunakan perpustakaan standar secara langsung. Benchmark konsisten menempatkan sqlc sebagai salah satu opsi tercepat, seringkali hanya sedikit lebih lambat atau bahkan sedikit lebih cepat daripada raw
database/sql
untuk operasi yang mirip. Misalnya, pada 10.000+ catatan, sqlc teramati sedikit mengungguli plaindatabase/sql
dalam throughput (kemungkinan karena menghindari beberapa boilerplate pemindaian dan menggunakan codegen yang efisien). Dengan sqlc, tidak ada pembangun query runtime – query Anda dieksekusi sebagai pernyataan yang disiapkan dengan sedikit overhead. Kuncinya adalah bahwa Anda sudah melakukan pekerjaan menulis query SQL optimal; sqlc hanya menghemat usaha memindai baris ke tipe Go. Dalam praktiknya, ini berarti skalabilitas yang sangat baik – sqlc akan menangani beban data besar sebagus SQL mentah, membuatnya menjadi pilihan terbaik ketika kecepatan mentah kritis. -
Ent: Kinerja Ent berada di antara pendekatan SQL mentah dan ORM tradisional. Karena Ent menghasilkan kode aman secara tipe, ia menghindari refleksi dan kebanyakan biaya komposisi query runtime. SQL yang dihasilkannya sangat dioptimalkan (Anda memiliki kontrol untuk menulis query efisien melalui API Ent), dan Ent memiliki lapisan caching internal untuk mengulang eksekusi query/hasil dalam beberapa kasus. Ini dapat mengurangi pengaksesan ulang database dalam alur kerja kompleks. Meskipun benchmark spesifik Ent vs yang lain bervariasi, banyak pengembang melaporkan bahwa Ent mengungguli GORM untuk operasi yang setara, terutama saat kompleksitas meningkat. Salah satu alasan adalah GORM mungkin menghasilkan query yang tidak optimal (misalnya, N+1 selects jika tidak menggunakan join/preload dengan hati-hati), sedangkan Ent mendorong pemuatan yang diminta secara eksplisit dan akan menggabungkan data dalam lebih sedikit query. Ent juga cenderung mengalokasikan lebih sedikit memori per operasi daripada GORM, yang dapat meningkatkan throughput dengan mengurangi tekanan pada garbage collector Go. Secara keseluruhan, Ent dibangun untuk kinerja tinggi dan skema besar – overheadnya rendah, dan dapat menangani query kompleks secara efisien – tetapi mungkin tidak cocok dengan throughput mentah SQL (sqlc) dalam setiap skenario. Ini adalah pilihan kuat jika Anda ingin kecepatan dan keamanan lapisan ORM.
-
Bun: Bun dibuat dengan kinerja dalam pikiran dan sering disebut sebagai alternatif yang lebih cepat daripada GORM. Ia menggunakan API fluent untuk membangun query SQL, tetapi pembangkit ini ringan. Bun tidak menyembunyikan SQL dari Anda – ini lebih seperti lapisan tipis di atas
database/sql
, yang berarti Anda hanya mengalami sedikit overhead di luar apa yang dilakukan perpustakaan standar Go. Pengguna telah mencatat peningkatan signifikan saat beralih dari GORM ke Bun dalam proyek besar: misalnya, satu laporan menyebutkan GORM “sangat lambat” untuk skala mereka, dan menggantinya dengan Bun (dan beberapa SQL mentah) menyelesaikan masalah kinerja mereka. Dalam benchmark seperti go-orm-benchmarks, Bun cenderung berada di puncak kecepatan untuk sebagian besar operasi (seringkali dalam 1,5× dari raw sqlx/sql) dan jauh di depan GORM dalam throughput. Ia juga mendukung insert batch, kontrol manual join vs query terpisah, dan optimasi lain yang dapat dimanfaatkan pengembang. Kesimpulan: Bun memberikan kinerja mendekati bare-metal, dan ini adalah pilihan yang baik ketika Anda ingin kenyamanan ORM tetapi tidak ingin mengorbankan kecepatan. Sifat SQL-first-nya memastikan Anda selalu dapat mengoptimalkan query jika yang dihasilkan tidak optimal.
Kesimpulan Kinerja: Jika tujuan utamanya adalah kinerja maksimal (misalnya, aplikasi data-intensif, mikroservis di bawah beban tinggi), sqlc atau bahkan panggilan database/sql
yang ditulis secara manual adalah pemenangnya. Mereka hampir tidak memiliki biaya abstraksi dan skalabilitasnya linear. Ent dan Bun juga berkinerja sangat baik dan dapat menangani query kompleks secara efisien – mereka mencapai keseimbangan antara kecepatan dan abstraksi. GORM menawarkan fitur paling banyak tetapi dengan biaya overhead; ini sangat diterima untuk banyak aplikasi, tetapi Anda harus waspada dampaknya jika Anda mengharapkan menangani volume data besar atau membutuhkan latensi ultra rendah. (Dalam kasus seperti itu, Anda mungkin mengurangi biaya GORM dengan menggunakan Joins
secara hati-hati alih-alih Preload
untuk mengurangi jumlah query, atau dengan memasukkan SQL mentah untuk jalur kritis, tetapi ini menambah kompleksitas.)
Pengalaman Pengembang dan Kemudahan Penggunaan
Pengalaman pengembang bisa bersifat subjektif, tetapi mencakup kurva pembelajaran, kejelasan API, dan seberapa produktif Anda bisa menjadi dalam coding sehari-hari. Berikut adalah perbandingan empat pilihan kami dalam hal kemudahan penggunaan dan alur kerja pengembangan:
-
GORM – Fitur Lengkap Tapi Ada Kurva Pembelajaran: GORM sering menjadi ORM pertama yang dicoba oleh pengembang Go baru karena menjanjikan pengalaman otomatis penuh (Anda mendefinisikan struct dan dapat langsung Create/Find tanpa menulis SQL). Dokumentasinya sangat komprehensif dengan banyak panduan, yang membantu. Namun, GORM memiliki cara sendiri dalam melakukan hal-hal (“pendekatan berbasis kode” untuk interaksi DB) dan bisa terasa tidak nyaman awalnya jika Anda terbiasa dengan SQL mentah. Banyak operasi umum sederhana (misalnya,
db.Find(&objs)
) mudah dilakukan, tetapi ketika Anda memasuki asosiasi, hubungan polimorfik, atau query lanjutan, Anda perlu mempelajari konvensi GORM (tag struct,Preload
vsJoins
, dll.). Inilah sebabnya mengapa sering disebutkan kurva pembelajaran awal yang curam. Setelah menaiki kurva tersebut, GORM bisa sangat produktif – Anda menghabiskan lebih sedikit waktu menulis SQL berulang dan lebih banyak waktu dalam logika Go. Faktanya, setelah menguasainya, banyak orang menemukan bahwa mereka bisa mengembangkan fitur lebih cepat dengan GORM daripada dengan perpustakaan tingkat rendah. Secara singkat, GORM DX: tinggi pada kompleksitas awal tetapi menjadi mulus dengan pengalaman. Komunitas besar berarti banyak contoh dan jawaban StackOverflow tersedia, dan ekosistem plugin yang kaya dapat menyederhanakan tugas (misalnya, plugin untuk penghapusan lembut, audit, dll.). Peringatan utamanya adalah Anda harus tetap sadar apa yang dilakukan GORM di bawah hood untuk menghindari jebakan (seperti query N+1 yang tidak disengaja). Namun, bagi pengembang yang bersedia menginvestasikan waktu pada GORM, memang terasa seperti solusi yang kuat dan terintegrasi yang menangani banyak hal untuk Anda. -
Ent – Schema-First dan Type-Safe: Ent dirancang secara eksplisit untuk meningkatkan pengalaman pengembang ORM. Anda mendeskripsikan skema Anda di satu tempat (kode Go) dan mendapatkan API yang aman secara tipe untuk digunakan – ini berarti tidak ada query yang bertipe string, dan banyak kesalahan ditangkap saat kompilasi. Misalnya, jika Anda mencoba merujuk bidang atau edge yang tidak ada, kode Anda sederhana tidak akan dikompilasi. Jaring pengaman ini adalah kemenangan besar untuk proyek besar. API Ent untuk membangun query fluent dan intuitif: Anda mengaitkan metode seperti
.Where(user.EmailEQ("alice@example.com"))
dan itu membaca hampir seperti bahasa Inggris. Pengembang yang datang dari ORM di bahasa lain sering menemukan pendekatan Ent alami (ini mirip dengan Entity Framework atau Prisma, tetapi dalam Go). Belajar Ent memerlukan memahami alur kerja pembangkitan kode. Anda perlu menjalankanentc generate
(atau menggunakango generate
) setiap kali Anda memodifikasi skema Anda. Ini adalah langkah tambahan, tetapi biasanya bagian dari proses pembangunan. Kurva pembelajaran untuk Ent adalah sedang – jika Anda tahu Go dan dasar-dasar SQL, konsep Ent (Field, Edge, dll.) adalah sederhana. Faktanya, banyak orang menemukan Ent lebih mudah untuk dipahami daripada GORM, karena Anda tidak perlu memikirkan SQL apa yang dihasilkan; seringkali Anda bisa memprediksi dari nama metode, dan Anda bisa mengeluarkan query untuk debugging jika diperlukan. Dokumentasi dan contoh Ent sangat baik, dan didukung oleh perusahaan memastikan bahwa ia aktif dipelihara. Secara keseluruhan DX dengan Ent: sangat ramah bagi mereka yang ingin kejelasan dan keamanan. Kode yang Anda tulis lebih panjang dibandingkan SQL mentah, tetapi bersifat self-documenting. Juga, refactoring lebih aman (mengganti nama bidang dalam skema dan menghasilkan ulang akan memperbarui semua penggunaan dalam query). Kekurangan mungkin adalah bahwa Anda sedikit terbatas oleh apa yang diberikan oleh pembangkitan kode Ent – jika Anda membutuhkan query yang sangat khusus, Anda mungkin harus menulisnya dengan API Ent (yang dapat menangani join kompleks, tetapi kadang-kadang Anda mungkin menemukan kasus yang lebih mudah ditulis dalam SQL mentah). Ent memungkinkan potongan SQL mentah ketika diperlukan, tetapi jika Anda sering melakukannya, Anda mungkin mempertanyakan apakah ORM adalah pilihan yang tepat. Secara ringkas, Ent menyediakan pengalaman pengembang yang mulus untuk sebagian besar logika CRUD dan query dengan sedikit kejutan, selama Anda bersedia menjalankan langkah pembangkitan kode dan mematuhi pola yang ditetapkan Ent. -
Bun – Lebih Dekat ke SQL, Lebih Sedikit Magic: Menggunakan Bun terasa berbeda dari menggunakan GORM atau Ent. Filosofi Bun adalah tidak menyembunyikan SQL — jika Anda tahu SQL, Anda sudah tahu bagaimana menggunakan Bun sebagian besar. Misalnya, untuk query pengguna Anda mungkin menulis:
db.NewSelect().Model(&users).Where("name = ?", name).Scan(ctx)
. Ini adalah API fluent tetapi sangat dekat dengan struktur pernyataan SELECT sebenarnya. Kurva pembelajaran untuk Bun umumnya rendah jika Anda nyaman dengan SQL itu sendiri. Ada sedikit “magic ORM” untuk dipelajari; Anda hanya perlu mempelajari nama metode untuk membangun query dan konvensi tag struct. Ini membuat Bun sangat mudah diakses bagi pengembang berpengalaman yang telah menggunakandatabase/sql
atau pembangkit query lain sepertisqlx
. Sebaliknya, seorang pemula yang tidak yakin dalam menulis SQL mungkin menemukan Bun sedikit kurang membantu daripada GORM – Bun tidak akan secara otomatis menghasilkan query kompleks untuk Anda melalui hubungan kecuali Anda menentukannya. Namun, Bun memang mendukung hubungan dan pemuasan yang diminta (Relation()
metode untuk menggabungkan tabel) – ia hanya melakukannya secara eksplisit, yang beberapa pengembang prefer untuk kejelasan. Pengalaman pengembang dengan Bun dapat dijelaskan sebagai ringan dan dapat diprediksi. Anda menulis sedikit lebih banyak kode daripada dengan GORM untuk beberapa operasi (karena Bun sering meminta Anda untuk secara eksplisit menentukan kolom atau join), tetapi sebagai imbalannya Anda memiliki lebih banyak kontrol dan visibilitas. Ada sedikit magic internal, sehingga debugging lebih mudah (Anda biasanya dapat mencatat string query yang dibangun oleh Bun). Dokumentasi Bun (panduan uptrace.dev) menyeluruh dan mencakup pola untuk migrasi, transaksi, dll., meskipun komunitas yang lebih kecil berarti lebih sedikit tutorial pihak ketiga. Aspek lain dari DX adalah alat yang tersedia: Bun sebagai ekstensi daridatabase/sql
berarti bahwa alat apa pun yang bekerja dengansql.DB
(seperti proxy debugging, logger query) bekerja dengan Bun dengan mudah. Secara ringkas, Bun menawarkan pengalaman tanpa bantuan: terasa seperti menulis SQL terstruktur dalam Go. Ini sangat baik untuk pengembang yang menghargai kontrol dan kinerja, tetapi mungkin tidak memberikan bantuan sebanyak sesuatu seperti GORM untuk pengembang yang kurang berpengalaman. Konsensus adalah bahwa Bun membuat hal-hal sederhana mudah dan hal-hal kompleks mungkin (seperti SQL mentah), tanpa memaksakan banyak kerangka pada Anda. -
sqlc – Tulis SQL, Dapatkan Kode Go: Pendekatan sqlc membalik narasi ORM biasa. Alih-alih menulis kode Go untuk menghasilkan SQL, Anda menulis SQL dan mendapatkan kode Go. Untuk pengembang yang menyukai SQL, ini luar biasa – Anda dapat menggunakan seluruh kekuatan SQL (join kompleks, CTE, fungsi window, dan sebagainya) dengan tidak ada batasan ORM. Kurva pembelajaran untuk sqlc itu sendiri sangat kecil. Jika Anda tahu cara menulis SELECT/INSERT/UPDATE dalam SQL, Anda sudah menyelesaikan bagian sulit. Anda memang perlu mempelajari cara mengomentari query dengan
-- name: Name :one/many/exec
dan mengatur file konfigurasi, tetapi itu sangat sederhana. Kode yang dihasilkan akan menjadi definisi fungsi yang sederhana, yang Anda panggil seperti fungsi Go apa pun. Kelebihan pengalaman pengembang: tidak ada API ORM untuk dipelajari, tidak ada kejutan – query berjalan tepat seperti yang ditulis. Anda menghindari seluruh kelas masalah ORM (seperti mencari tahu mengapa ORM menghasilkan JOIN tertentu atau bagaimana menyesuaikan query). Selain itu, tinjauan kode Anda dapat mencakup tinjauan SQL itu sendiri, yang sering lebih jelas untuk logika kompleks. Keuntungan besar lainnya dalam DX: keamanan tipe dan dukungan IDE – metode dan struct yang dihasilkan dapat diakses langsung dalam editor Anda, alat refactor bekerja pada mereka, dll., dibandingkan query string mentah yang tidak jelas bagi IDE. Di sisi negatif, sqlc memang memerlukan Anda untuk mengelola skrip SQL. Ini berarti jika skema atau kebutuhan Anda berubah, Anda harus secara manual memperbarui atau menambahkan SQL relevan dan menjalankan codegen ulang. Ini tidak sulit, tetapi lebih manual daripada hanya memanggil metode ORM. Selain itu, query dinamis (di mana bagian dari SQL bersifat kondisional) bisa merepotkan – Anda harus menulis beberapa variasi SQL atau menggunakan trik sintaks SQL. Beberapa pengembang menyebutkan ini sebagai keterbatasan pendekatan sqlc. Dalam praktiknya, Anda sering dapat mengatur akses data Anda sehingga Anda tidak perlu SQL dinamis yang terlalu berlebihan, atau Anda dapat memanggil rawdatabase/sql
untuk kasus ujung tersebut. Namun, ini adalah pertimbangan: sqlc luar biasa untuk query yang didefinisikan dengan baik, kurang baik untuk pembangunan query ad-hoc. Secara ringkas, untuk pengembang yang mahir dengan SQL, menggunakan sqlc terasa alami dan sangat efisien. Ada sangat sedikit hal baru untuk dipelajari, dan ini menghilangkan boilerplate Go yang berulang. Untuk pengembang yang kurang nyaman dengan SQL, sqlc mungkin awalnya lebih lambat untuk digunakan (dibandingkan ORM yang, misalnya, menghasilkan query otomatis untuk CRUD dasar). Namun, banyak pengembang Go menganggap sqlc sebagai wajib karena ia menemukan titik ideal: kontrol manual dengan keamanan tinggi dan tanpa biaya runtime.
Popularitas dan Dukungan Ekosistem
Adopsi dan dukungan komunitas dapat memengaruhi pilihan Anda — sebuah library yang populer berarti lebih banyak kontribusi dari komunitas, pemeliharaan yang lebih baik, dan lebih banyak sumber daya untuk dipelajari.
-
GORM: Sebagai yang paling tua dan paling matang dari keempatnya, GORM memiliki basis pengguna terbesar dan ekosistem yang paling luas. Saat ini, GORM adalah ORM Go dengan jumlah bintang terbanyak di GitHub (lebih dari 38k bintang) dan digunakan dalam berbagai proyek produksi. Pemelihara GORM aktif, dan proyek ini secara teratur diperbarui (GORM v2 adalah overhaul besar yang meningkatkan kinerja dan arsitektur). Keuntungan besar dari popularitas GORM adalah kemakmuran ekstensi dan integrasi. Ada plugin resmi dan pihak ketiga untuk hal-hal seperti driver database (misalnya untuk PostgreSQL, MySQL, SQLite, SQL Server, ClickHouse), yang tersedia secara langsung. GORM juga mendukung berbagai kasus penggunaan: migrasi, pembuatan skema otomatis, penghapusan lunak, bidang JSON (dengan
gorm.io/datatypes
), pencarian penuh teks, dll., sering kali melalui fitur bawaan atau aksesori. Komunitas telah menghasilkan berbagai alat sepertigormt
(untuk menghasilkan definisi struct dari database yang sudah ada), serta banyak tutorial dan contoh. Jika Anda menghadapi masalah, pencarian cepat kemungkinan besar akan menemukan masalah atau pertanyaan Stack Overflow yang diajukan orang lain. Ringkasan ekosistem: GORM sangat didukung. Ini adalah pilihan ORM “default” bagi banyak orang, yang berarti Anda akan menemukannya dalam framework dan boilerplate. Di sisi lain, ukuran yang sangat besar ini dapat membuatnya terasa berat, tetapi bagi banyak orang itu adalah pertukaran yang layak untuk kedalaman komunitas. -
Ent: Meskipun lebih baru (dibuka sekitar tahun 2019), Ent telah berkembang menjadi komunitas yang kuat. Dengan sekitar 16k bintang dan didukung oleh Linux Foundation, ini bukan proyek pinggiran. Perusahaan besar mulai menggunakan Ent karena keunggulan berbasis skemanya, dan pemelihara (di Ariga) menyediakan dukungan enterprise yang merupakan tanda kepercayaan untuk penggunaan kritis bisnis. Ekosistem sekitar Ent sedang berkembang: ada ekstensi Ent (ent/go) untuk hal-hal seperti integrasi OpenAPI/GraphQL, integrasi gRPC, dan bahkan alat migrasi SQL yang bekerja dengan skema Ent. Karena Ent menghasilkan kode, beberapa pola ekosistem berbeda — misalnya, jika Anda ingin mengintegrasikan dengan GraphQL, Anda mungkin menggunakan pembangkitan kode Ent untuk menghasilkan resolver GraphQL. Sumber daya pembelajaran untuk Ent baik (dokumentasi resmi dan proyek contoh yang menutupi aplikasi sederhana). Forum komunitas dan diskusi GitHub aktif dengan pertanyaan desain skema dan tips. Dalam hal dukungan komunitas, Ent jelas melewati fase “pengadopsi awal” dan dianggap siap produksi dan andal. Mungkin belum memiliki jawaban Stack Overflow sebanyak GORM, tetapi sedang mengejar dengan cepat. Satu hal yang perlu dicatat: karena Ent sedikit lebih opiniatif (misalnya, ingin mengelola skema), Anda kemungkinan besar akan menggunakan Ent secara mandiri daripada bersama ORM lain. Ent tidak memiliki “plugin” dalam cara yang sama seperti GORM, tetapi Anda dapat menulis template kustom untuk memperluas pembangkitan kode atau menghubungkan ke acara siklus hidup (Ent memiliki dukungan hook/middleware untuk klien yang dibangkitkan). Dukungan jangka panjang yang diindikasikan oleh pendukung foundation membuat memilih Ent menjadi pilihan aman jika modelnya cocok dengan kebutuhan Anda.
-
Bun: Bun (bagian dari suite open-source Uptrace) sedang mendapatkan popularitas, terutama di kalangan penggemar library
go-pg
yang kini tidak lagi diperbarui. Dengan sekitar 4.3k bintang, ini adalah komunitas terkecil dalam perbandingan ini, tetapi ini adalah proyek yang sangat aktif. Pemelihara responsif dan telah dengan cepat menambahkan fitur. Komunitas Bun antusias tentang kinerjanya. Anda akan menemukan diskusi di forum Go dan Reddit dari pengembang yang beralih ke Bun karena kecepatannya. Namun, karena basis pengguna lebih kecil, Anda mungkin tidak selalu menemukan jawaban untuk pertanyaan niche secara langsung — terkadang Anda perlu membaca dokumen/sumber atau bertanya di GitHub atau Discord Bun (Uptrace menyediakan obrolan komunitas). Ekosistem ekstensi lebih terbatas: Bun memiliki library migrasi sendiri, loader fixture, dan terhubung ke alat observabilitas Uptrace, tetapi Anda tidak akan menemukan jumlah plugin yang melimpah seperti pada GORM. Dengan demikian, Bun kompatibel dengan penggunaansql.DB
, sehingga Anda dapat bercampur-campur — misalnya, menggunakangithub.com/jackc/pgx
sebagai driver di bawah atau mengintegrasikan dengan paket lain yang mengharapkan*sql.DB
. Bun tidak memaksa Anda. Dalam hal dukungan, karena lebih baru, dokumentasi terkini dan contoh modern (sering menunjukkan penggunaan dengan konteks dan lainnya). Dokumentasi resmi membandingkan Bun langsung dengan GORM dan Ent, yang sangat membantu. Jika ukuran komunitas menjadi kekhawatiran, satu strategi yang mungkin adalah mengadopsi Bun karena keunggulannya tetapi menjaga penggunaannya relatif dangkal (misalnya, Anda bisa menggantinya dengan solusi lain jika diperlukan karena tidak memaksa abstraksi berat). Dalam hal apa pun, trajectori Bun sedang naik, dan ia mengisi niche spesifik (ORM berorientasi kinerja) yang memberinya daya tahan. -
sqlc: sqlc sangat populer dalam komunitas Go, terbukti dari sekitar 15.9k bintang dan banyak pendukung terutama dalam lingkaran yang peduli pada kinerja. Alat ini sering direkomendasikan dalam diskusi tentang “menghindari ORM” karena mencapai keseimbangan yang baik. Alat ini dikelola oleh kontributor (termasuk penulis asli, yang aktif dalam meningkatkannya). Karena lebih mirip compiler daripada library runtime, ekosistemnya berputar di sekitar integrasi: misalnya, editor/IDE dapat memiliki penyorotan sintaks untuk file
.sql
dan Anda menjalankansqlc generate
sebagai bagian dari build atau pipeline CI Anda. Komunitas telah membuat template dan contoh repo dasar tentang cara mengatur kode dengan sqlc (sering dipasangkan dengan alat migrasi seperti Flyway atau Golang-Migrate untuk versi skema, karena sqlc sendiri tidak mengelola skema). Ada Slack/Discord resmi untuk sqlc di mana Anda dapat bertanya, dan isu di GitHub cenderung mendapatkan perhatian. Banyak pola umum (seperti cara menangani nilai nullable atau bidang JSON) didokumentasikan dalam dokumen sqlc atau memiliki posting blog komunitas. Satu hal yang perlu ditekankan: sqlc bukan spesifik Go — ia dapat menghasilkan kode dalam bahasa lain (seperti TypeScript, Python). Ini memperluas komunitasnya di luar Go, tetapi secara spesifik dalam Go, ia sangat dihormati. Jika Anda memilih sqlc, Anda berada dalam kelompok yang baik: digunakan dalam produksi oleh banyak startup dan perusahaan besar (seperti yang ditunjukkan oleh komunitas dan sponsor yang tercantum di repo). Pertimbangan ekosistem utama adalah bahwa karena sqlc tidak menyediakan fitur runtime seperti ORM, Anda mungkin perlu menarik library lain untuk hal-hal seperti transaksi (meskipun Anda dapat menggunakansql.Tx
dengan mudah menggunakan sqlc) atau mungkin penutup DAL ringan. Dalam praktiknya, sebagian besar menggunakan sqlc bersama dengan library standar (untuk transaksi, pembatalan konteks, dll., Anda menggunakan idiomadatabase/sql
secara langsung dalam kode Anda). Ini berarti kurangnya ketergantungan vendor — berpindah dari sqlc hanya berarti menulis lapisan data sendiri, yang seberat menulis SQL (yang sudah Anda lakukan). Secara keseluruhan, komunitas dan dukungan untuk sqlc kuat, dengan banyak yang merekomendasikannya sebagai “wajib digunakan” untuk proyek Go yang berinteraksi dengan database SQL karena kesederhanaan dan keandalannya.
Setelan Fitur dan Ekstensibilitas
Setiap alat ini menawarkan himpunan fitur yang berbeda. Di sini kami membandingkan kemampuan mereka dan seberapa ekstensibel mereka untuk kasus penggunaan lanjutan:
- Fitur GORM: GORM bertujuan menjadi ORM penuh layanan. Daftar fiturnya sangat luas:
- Banyak Database: Dukungan kelas satu untuk PostgreSQL, MySQL, SQLite, SQL Server, dan lainnya. Beralih DB biasanya se mudah mengganti driver koneksi.
- Migrasi: Anda dapat mengotomatisasi migrasi skema dari model Anda (
db.AutoMigrate(&User{})
akan menciptakan atau mengubah tabelusers
). Meskipun nyaman, hati-hati menggunakan migrasi otomatis di produksi — banyak yang menggunakan untuk dev dan memiliki migrasi yang lebih terkontrol untuk prod. - Hubungan: Tag struct GORM (
gorm:"foreignKey:...,references:..."
) memungkinkan Anda mendefinisikan satu-ke-banyak, banyak-ke-banyak, dll. Ia dapat menangani tabel penghubung untuk banyak-ke-banyak dan memilikiPreload
untuk memuat hubungan secara cepat. GORM secara default menggunakan pengambilan data lambat (yaitu, query terpisah) ketika Anda mengakses bidang terkait, tetapi Anda dapat menggunakanPreload
atauJoins
untuk menyesuaikan hal itu. Versi terbaru juga memiliki API berbasis generics untuk query asosiasi yang lebih mudah. - Transaksi: GORM memiliki wrapper transaksi yang mudah digunakan (
db.Transaction(func(tx *gorm.DB) error { ... })
) dan bahkan dukungan untuk transaksi bersarang (savepoints). - Hooks dan Callbacks: Anda dapat mendefinisikan metode seperti
BeforeCreate
,AfterUpdate
pada struct model Anda, atau mendaftarkan callback global yang akan dipanggil GORM pada acara siklus hidup tertentu. Ini sangat bagus untuk hal-hal seperti mengatur timestamp secara otomatis atau perilaku penghapusan lunak. - Ekstensibilitas: Sistem plugin GORM (
gorm.Plugin
interface) memungkinkan memperluas fungsionalitasnya. Contoh: paketgorm-gen
menghasilkan metode query yang aman tipe (jika Anda lebih suka pemeriksaan query waktu kompilasi), atau plugin komunitas untuk audit, multi-tenancy, dll. Anda juga dapat kembali ke SQL mentah kapan saja melaluidb.Raw("SELECT ...", params).Scan(&result)
. - Lainnya: GORM mendukung kunci primer komposit, menanam model, asosiasi polimorfik, dan bahkan penyelesaian skema untuk menggunakan beberapa database (untuk replika baca, sharding, dll.).
Secara keseluruhan, GORM sangat ekstensibel dan fiturnya sangat luas. Hampir semua fitur ORM yang mungkin Anda inginkan memiliki mekanisme bawaan atau pola yang didokumentasikan dalam GORM. Biaya dari kelebaran ini adalah kompleksitas dan sedikit ketat (Anda sering perlu menyesuaikan dengan cara GORM melakukan hal-hal). Tapi jika Anda membutuhkan solusi satu atap, GORM memberikan.
- Fitur Ent: Filosofi Ent berpusat pada skema sebagai kode. Fitur utama termasuk:
- Definisi Skema: Anda dapat mendefinisikan bidang dengan batasan (unik, nilai default, enum, dll.), dan edge (relasi) dengan kardinalitas (satu-ke-banyak, dll.). Ent menggunakan ini untuk menghasilkan kode dan juga dapat menghasilkan SQL migrasi untuk Anda (ada komponen
ent/migrate
yang dapat menghasilkan SQL diff antara skema saat ini dan skema yang diinginkan). - Keamanan Tipe dan Validasi: Karena bidang bertipe kuat, Anda tidak bisa, misalnya, secara tidak sengaja mengatur bidang integer ke string. Ent juga memungkinkan tipe bidang kustom (misalnya, Anda dapat mengintegrasikan dengan
sql.Scanner
/driver.Valuer
untuk bidang JSONB atau tipe kompleks lainnya). - Pembangkit Query: API query yang dihasilkan Ent mencakup sebagian besar konstruksi SQL: Anda dapat melakukan selects, filter, pengurutan, batas, agregasi, joins di edge, bahkan subqueries. Ini ekspresif — misalnya, Anda dapat menulis
client.User.Query().WithOrders(func(q *ent.OrderQuery) { q.Limit(5) }).Where(user.StatusEQ(user.StatusActive)).All(ctx)
untuk mendapatkan pengguna aktif dengan 5 pesanan pertama mereka, dalam satu go. - Transaksi: Klien Ent mendukung transaksi dengan menampilkan varian transaksional dari klien (melalui
tx, err := client.Tx(ctx)
yang menghasilkanent.Tx
yang dapat Anda gunakan untuk melakukan beberapa operasi dan kemudian commit atau rollback). - Hooks dan Middleware: Ent memungkinkan pendaftaran hooks pada operasi create/update/delete — ini seperti interceptor di mana Anda dapat, misalnya, mengisi bidang secara otomatis atau menerapkan aturan kustom. Ada juga middleware untuk klien untuk mengelilingi operasi (berguna untuk logging, instrumenasi).
- Ekstensibilitas: Meskipun Ent tidak memiliki “plugin” secara harfiah, pembangkitan kode-nya berbasis template dan Anda dapat menulis template kustom jika Anda perlu memperluas kode yang dihasilkan. Banyak fitur lanjutan telah diimplementasikan dengan cara ini: misalnya, integrasi dengan OpenTelemetry untuk melacak panggilan DB, atau menghasilkan resolver GraphQL dari skema Ent, dll. Ent juga memungkinkan penggunaan SQL mentah ketika diperlukan melalui paket
entsql
atau dengan mendapatkan driver dasar. Kemampuan untuk menghasilkan kode tambahan berarti tim dapat menggunakan Ent sebagai dasar dan menumpuk pola mereka sendiri di atasnya, jika diperlukan. - Integrasi GraphQL/REST: Titik jual besar dari pendekatan graph-based Ent adalah bahwa cocok dengan GraphQL — skema ent Anda dapat dipetakan hampir langsung ke skema GraphQL. Ada alat yang dapat mengotomatisasi banyak hal itu. Ini bisa menjadi kemenangan produktivitas jika Anda membangun server API.
- Peningkatan Kinerja: Misalnya, Ent dapat memuat edge terkait secara batch untuk menghindari N+1 queries (ia memiliki API pemuatan cepat
.With<EdgeName>()
). Ia akan menggunakan JOIN atau query tambahan di bawahnya secara optimal. Selain itu, penyimpanan cache hasil query (di memori) dapat diaktifkan untuk menghindari mengakses DB untuk query yang identik dalam jangka pendek.
Secara ringkas, setelan fitur Ent dikembangkan untuk proyek besar, yang dapat dipelihara. Ia mungkin kehilangan beberapa fitur siap pakai GORM (misalnya, migrasi skema otomatis GORM vs skrip migrasi yang dihasilkan Ent — Ent memilih memisahkan kekhawatiran tersebut), tetapi ia mengimbanginya dengan alat pengembangan yang kuat dan keamanan tipe. Ekstensibilitas dalam Ent adalah tentang menghasilkan apa yang Anda butuhkan — sangat fleksibel jika Anda bersedia menyelami bagaimana entc (codegen) bekerja.
- Fitur Bun: Bun berfokus menjadi alat kuat bagi mereka yang mengenal SQL. Beberapa fitur dan titik ekstensibilitas:
- Pembangkit Query: Di inti Bun adalah pembangkit query yang lancar yang mendukung sebagian besar konstruksi SQL (SELECT dengan joins, CTEs, subqueries, serta INSERT, UPDATE dengan dukungan bulk). Anda dapat memulai query dan menyesuaikannya secara mendalam, bahkan menyisipkan SQL mentah
(
.Where("some_condition (?)", value)
). - Fitur khusus PostgreSQL: Bun memiliki dukungan bawaan untuk tipe array Postgres, JSON/JSONB (pemetaan ke
[]<type>
ataumap[string]interface{}
atau tipe kustom), dan mendukung pemindaian ke tipe komposit. Misalnya, jika Anda memiliki kolom JSONB, Anda dapat memetakan ke struct Go dengan tagjson:
dan Bun akan menangani marshaling untuk Anda. Ini adalah kekuatan dibandingkan beberapa ORM yang memperlakukan JSONB sebagai tidak transparan. - Hubungan/Pemuatan Cepat: Seperti yang ditunjukkan sebelumnya, Bun memungkinkan Anda mendefinisikan tag struct untuk hubungan dan kemudian Anda dapat menggunakan
.Relation("FieldName")
dalam query untuk menggabungkan dan memuat entitas terkait. Secara default,.Relation
menggunakan LEFT JOIN (Anda dapat mensimulasikan inner joins atau jenis lain dengan menambahkan kondisi). Ini memberi Anda kontrol halus atas cara data terkait diambil (dalam satu query vs beberapa). Jika Anda lebih suka query manual, Anda selalu dapat menulis join langsung dalam pembangkit SQL Bun. Berbeda dengan GORM, Bun tidak akan memuat hubungan secara otomatis tanpa Anda meminta, yang menghindari masalah N+1 yang tidak disengaja. - Migrasi: Bun menyediakan alat migrasi terpisah (di
github.com/uptrace/bun/migrate
). Migrasi didefinisikan dalam Go (atau string SQL) dan diberi versi. Ini tidak seotomatis GORM’s auto-migrate, tetapi kuat dan terintegrasi dengan library secara baik. Ini sangat bagus untuk menjaga perubahan skema eksplisit. - Ekstensibilitas: Bun dibangun pada antarmuka yang mirip dengan database/sql — bahkan mengemas
*sql.DB
. Anda dapat menggunakan alat tingkat bawah apa pun dengan itu (misalnya, Anda dapat menjalankan query*pgx.Conn
jika diperlukan dan masih memindaikan ke model Bun). Bun memungkinkan scanner nilai kustom, jadi jika Anda memiliki tipe kompleks yang ingin disimpan, Anda implementasikansql.Scanner
/driver.Valuer
dan Bun akan menggunakan itu. Untuk memperluas fungsionalitas Bun, karena relatif sederhana, banyak orang hanya menulis fungsi bantu tambahan di atas API Bun dalam proyek mereka sendiri daripada plugin terpisah. Library itu sendiri sedang berkembang, jadi fitur baru (seperti bantuan query tambahan atau integrasi) sedang ditambahkan oleh pemelihara. - Fitur lain: Bun mendukung pembatalan konteks (semua query menerima
ctx
), memiliki pool koneksi melaluidatabase/sql
di bawahnya (konfigurasinya ada di sana), dan mendukung caching pernyataan yang disiapkan (melalui driver jika menggunakanpgx
). Ada juga fitur yang bagus di mana Bun dapat memindaikan ke pointer struct atau slice primitif dengan mudah (misalnya, memilih satu kolom ke[]string
langsung). Kebijakan kecil seperti ini yang membuat Bun menyenangkan bagi mereka yang tidak menyukai kode pemindaian yang berulang.
Secara ringkas, setelan fitur Bun mencakup 90% kebutuhan ORM tetapi dengan penekanan pada transparansi dan kinerja. Ia mungkin tidak memiliki semua fitur (misalnya, tidak melakukan pembaruan skema otomatis atau memiliki pola aktiv record), tetapi ia menyediakan blok bangunan untuk menerapkan apa pun yang Anda butuhkan di atasnya. Karena masih muda, harapkan setelan fiturnya terus berkembang, diarahkan oleh kasus penggunaan dunia nyata (pemelihara sering menambahkan fitur saat pengguna meminta).
- Fitur sqlc: “Fitur” sqlc sangat berbeda karena ini adalah generator:
- Dukungan SQL penuh: Fitur terbesar adalah bahwa Anda menggunakan fitur PostgreSQL sendiri secara langsung. Jika Postgres mendukungnya, Anda dapat menggunakan dalam sqlc. Ini termasuk CTEs, fungsi window, operator JSON, query spasial (PostGIS), dll. Tidak perlu library itu sendiri untuk mengimplementasikan sesuatu khusus untuk menggunakan ini.
- Pemetaan tipe: sqlc cerdas dalam memetakan tipe SQL ke tipe Go. Ia menangani tipe standar dan memungkinkan Anda mengonfigurasi atau memperluas pemetaan untuk tipe kustom atau enum. Misalnya, Postgres
UUID
dapat dipetakan ke tipegithub.com/google/uuid
jika Anda ingin, atau tipe domain dapat dipetakan ke tipe Go dasar. - Pengelolaan null: Ia dapat menghasilkan
sql.NullString
atau pointer untuk kolom nullable, tergantung preferensi Anda, sehingga Anda tidak perlu berjuang dengan pemindaian null. - Operasi batch: Meskipun sqlc sendiri tidak menyediakan API tingkat tinggi untuk batching, Anda pasti dapat menulis SQL insert bulk dan menghasilkan kode untuk itu. Atau memanggil prosedur penyimpanan — ini adalah fitur lain: karena ini SQL, Anda dapat memanfaatkan prosedur penyimpanan atau fungsi DB, dan sqlc menghasilkan wrapper Go.
- Query multi-statement: Anda dapat menempatkan beberapa pernyataan SQL dalam satu query bernama dan sqlc akan menjalankannya dalam transaksi (jika driver mendukungnya), mengembalikan hasil dari query terakhir atau apa pun yang Anda tentukan. Ini adalah cara untuk melakukan sesuatu seperti “create dan kemudian select” dalam satu panggilan.
- Ekstensibilitas: Sebagai compiler, ekstensibilitas datang dalam bentuk plugin untuk bahasa baru atau kontribusi komunitas untuk mendukung konstruksi SQL baru. Misalnya, jika tipe data PostgreSQL baru muncul, sqlc dapat diperbarui untuk mendukung pemetaannya. Dalam aplikasi Anda, Anda mungkin memperluas sekitar sqlc dengan menulis fungsi wrapper. Karena kode yang dihasilkan berada di bawah kendali Anda, Anda bisa memodifikasi — meskipun biasanya Anda tidak akan, Anda akan menyesuaikan SQL dan menghasilkan ulang. Jika diperlukan, Anda selalu dapat mencampur panggilan
database/sql
mentah dengan sqlc dalam kodebase Anda (tidak ada konflik, karena sqlc hanya menghasilkan beberapa kode Go). - Ketergantungan runtime minimal: Kode yang dihasilkan sqlc biasanya hanya bergantung pada
database/sql
standar (dan driver spesifik seperti pgx). Tidak ada library runtime berat; hanya beberapa tipe bantu. Ini berarti tidak ada beban ekstra dari sisi library di produksi — semua pekerjaan dilakukan di waktu kompilasi. Ini juga berarti Anda tidak akan mendapatkan fitur seperti cache objek atau identity map (seperti beberapa ORM memiliki) — jika Anda membutuhkan caching, Anda akan menerapkannya di lapisan layanan Anda atau menggunakan library terpisah.
Secara efektif, “fitur” sqlc adalah bahwa ia mengurangi jarak antara database SQL Anda dan kode Go Anda tanpa menambahkan hal-hal ekstra di tengah. Ini adalah alat khusus — ia tidak melakukan migrasi, tidak melacak status objek, dll., secara desain. Masalah-masalah tersebut ditinggalkan ke alat lain atau ke pengembang. Ini menarik jika Anda ingin lapisan data yang ramping, tetapi jika Anda mencari solusi satu dan selesai yang menangani segala sesuatu dari skema hingga query hingga hubungan dalam kode, sqlc sendiri bukanlah jawabannya — Anda akan memadukannya dengan pola atau alat lain.
Untuk merangkum bagian ini, GORM adalah mesin kuat fitur dan pilihan jelas jika Anda membutuhkan ORM yang matang dan ekstensibel yang dapat disesuaikan melalui plugin. Ent menawarkan pendekatan modern dan aman tipe terhadap fitur, memprioritaskan kebenaran dan pemeliharaan (dengan hal-hal seperti codegen, hooks, dan integrasi ke lapisan API). Bun menyediakan esensial dan mempercayakan pada keahlian SQL, membuatnya mudah diperluas dengan menulis lebih banyak SQL atau wrapper kecil. sqlc menghilangkan fitur ke tingkat logam — secara esensial sekaya SQL itu sendiri, tetapi segala sesuatu di luar itu (caching, dll.) adalah tanggung jawab Anda untuk menumpuknya.
Contoh Kode: Operasi CRUD dalam Setiap ORM
Tidak ada yang lebih baik untuk mengilustrasikan perbedaan daripada melihat bagaimana setiap alat menangani operasi CRUD dasar untuk model sederhana. Mari asumsikan kita memiliki model User
dengan bidang ID
, Name
, dan Email
. Di bawah ini adalah potongan kode berdampingan untuk membuat, membaca, memperbarui, dan menghapus pengguna dalam setiap perpustakaan, menggunakan PostgreSQL sebagai database.
Catatan: Dalam semua kasus, asumsikan kita sudah memiliki koneksi database yang telah dibuat (misalnya, db
atau client
), dan penanganan kesalahan dihilangkan untuk kejelasan. Tujuannya adalah membandingkan API dan tingkat kerumitan setiap pendekatan.
GORM (Gaya Active Record)
// Definisi model
type User struct {
ID uint `gorm:"primaryKey"`
Name string
Email string
}
// Membuat pengguna baru
user := User{Name: "Alice", Email: "alice@example.com"}
db.Create(&user) // INSERT INTO users (name,email) VALUES ('Alice','alice@example.com')
// Membaca (mencari berdasarkan kunci primer)
var u User
db.First(&u, user.ID) // SELECT * FROM users WHERE id = X LIMIT 1
// Memperbarui (kolom tunggal)
db.Model(&u).Update("Email", "alice_new@example.com")
// (menghasilkan: UPDATE users SET email='alice_new@example.com' WHERE id = X)
// Menghapus
db.Delete(&User{}, u.ID) // DELETE FROM users WHERE id = X
Ent (Codegen, API yang lancar)
// (Schema Ent didefinisikan di tempat lain dan kode dihasilkan. Asumsikan client adalah ent.Client)
// Membuat pengguna baru
u, err := client.User.
Create().
SetName("Alice").
SetEmail("alice@example.com").
Save(ctx)
// SQL: INSERT INTO users (name, email) VALUES ('Alice','alice@example.com') RETURNING id, name, email
// Membaca (berdasarkan ID)
u2, err := client.User.Get(ctx, u.ID)
// SQL: SELECT * FROM users WHERE id = X
// Memperbarui (kolom tunggal)
u3, err := client.User.
UpdateOneID(u.ID).
SetEmail("alice_new@example.com").
Save(ctx)
// SQL: UPDATE users SET email='alice_new@example.com' WHERE id = X RETURNING id, name, email
// Menghapus
err = client.User.DeleteOneID(u.ID).Exec(ctx)
// SQL: DELETE FROM users WHERE id = X
Bun
// Definisi model
type User struct {
bun.BaseModel `bun:"table:users"`
ID int64 `bun:",pk,autoincrement"`
Name string `bun:",notnull"`
Email string `bun:",unique,notnull"`
}
// Membuat pengguna baru
user := &User{Name: "Alice", Email: "alice@example.com"}
_, err := db.NewInsert().Model(user).Exec(ctx)
// INSERT INTO users (name, email) VALUES ('Alice','alice@example.com')
// Membaca (mencari berdasarkan ID)
var u User
err = db.NewSelect().Model(&u).
Where("id = ?", user.ID).
Scan(ctx)
// SELECT * FROM users WHERE id = X
// Memperbarui (kolom tunggal)
_, err = db.NewUpdate().Model(&u).
Set("email = ?", "alice_new@example.com").
Where("id = ?", u.ID).
Exec(ctx)
// UPDATE users SET email='alice_new@example.com' WHERE id = X
// Menghapus
_, err = db.NewDelete().Model((*User)(nil)).
Where("id = ?", u.ID).
Exec(ctx)
// DELETE FROM users WHERE id = X
sqlc
// Asumsikan kita menulis SQL dalam file dan sqlc menghasilkan struktur Queries dengan metode.
queries := New(db) // New menerima *sql.DB (atau pgx.Conn) dan mengembalikan Queries yang dihasilkan
// Membuat pengguna baru (metode yang dihasilkan mengeksekusi INSERT dan memindai hasil)
newUser, err := queries.CreateUser(ctx, "Alice", "alice@example.com")
// SQL dalam queries.sql -> INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email
// Membaca (berdasarkan ID)
user, err := queries.GetUser(ctx, newUser.ID)
// SQL -> SELECT id, name, email FROM users WHERE id = $1
// Memperbarui (email berdasarkan ID)
updatedUser, err := queries.UpdateUserEmail(ctx, newUser.ID, "alice_new@example.com")
// SQL -> UPDATE users SET email=$2 WHERE id = $1 RETURNING id, name, email
// Menghapus
err = queries.DeleteUser(ctx, newUser.ID)
// SQL -> DELETE FROM users WHERE id = $1
Seperti yang ditunjukkan kode di atas, setiap pendekatan memiliki perasaan yang berbeda:
-
GORM menggunakan metode struct dan penambahan lancar pada
db.Model(&obj)
atau langsung pada objekdb
. Ia mengisi struct dengan nilai yang dikembalikan (misalnya, setelahCreate
,user.ID
diatur). Ia juga menyembunyikan detail SQL secara dirancang – Anda umumnya tidak melihat query kecuali debugging. -
Ent menggunakan API yang dihasilkan secara lancar. Perhatikan bagaimana metode seperti
Create().SetX().Save(ctx)
atauUpdateOneID(id).SetX().Save(ctx)
jelas memisahkan fase membangun vs mengeksekusi. Ent mengembalikan objek ent.Type (yang sesuai dengan baris) dan kesalahan, mirip dengan cara query SQL akan mengembalikan hasil atau kesalahan. -
Bun memerlukan penentuan yang lebih eksplisit (misalnya, menggunakan
Set("email = ?", ...)
untuk pembaruan), yang sangat mirip dengan menulis SQL tetapi dengan sintaks Go. Setelah insert, structuser
tidak diisi secara otomatis dengan ID baru kecuali Anda menambahkan klausaRETURNING
(Bun mendukung.Returning()
jika diperlukan). Contoh di atas menjaga hal-hal sederhana. -
sqlc tampak seperti memanggil fungsi Go apa pun. Kita memanggil
queries.CreateUser
, dll., dan di bawah hood itu adalah mengeksekusi pernyataan yang dipersiapkan. SQL ditulis dalam file eksternal, jadi meskipun Anda tidak melihatnya dalam kode Go, Anda memiliki kendali penuh atasnya. Objek yang dikembalikan (misalnya,newUser
) adalah struktur Go biasa yang dihasilkan oleh sqlc untuk memodelkan data.
Seseorang dapat mengamati perbedaan tingkat kerumitan (GORM sangat ringkas; Bun dan sqlc memerlukan sedikit lebih banyak pengetikan dalam kode atau SQL) dan perbedaan gaya (Ent dan GORM menawarkan abstraksi tingkat tinggi sementara Bun dan sqlc lebih dekat ke query mentah). Bergantung pada preferensi Anda, Anda mungkin lebih memilih eksplisitas daripada kependekan atau sebaliknya.
TL;DR
Memilih “yang benar” ORM atau perpustakaan database dalam Go bergantung pada kebutuhan aplikasi Anda dan preferensi tim Anda:
-
GORM adalah pilihan yang baik jika Anda ingin ORM yang teruji dan menangani banyak hal untuk Anda. Ia bercahaya dalam pengembangan cepat aplikasi CRUD di mana kenyamanan dan fitur kaya lebih penting daripada mengoptimalkan setiap tetes kinerja. Dukungan komunitas dan dokumentasi sangat baik, yang dapat menghaluskan sisi kasar dari kurva pembelajaran. Perhatikan untuk menggunakan fitur dengan tepat (misalnya, gunakan
Preload
atauJoins
untuk menghindari masalah lazy-loading) dan harapkan sedikit overhead. Sebagai pertukaran, Anda mendapatkan produktivitas dan solusi satu atap untuk sebagian besar masalah. Jika Anda membutuhkan hal-hal seperti dukungan database ganda atau ekosistem plugin yang luas, GORM memiliki Anda tertutup. -
Ent menarik bagi mereka yang memprioritaskan keamanan tipe, kejelasan, dan keterpeliharaan. Ia cocok untuk kodebase besar di mana perubahan skema sering terjadi dan Anda ingin kompiler di pihak Anda untuk menangkap kesalahan. Ent mungkin melibatkan lebih banyak desain awal (mendefinisikan skema, menjalankan pembangkitan), tetapi akan membuahkan hasil saat proyek berkembang – kode Anda tetap kuat dan ramah refactor. Dalam hal kinerja, ia dapat menangani beban berat dan query kompleks secara efisien, seringkali lebih baik daripada ORM active-record, berkat pembangkitan SQL yang dioptimalkan dan caching. Ent sedikit kurang “plug-and-play” untuk skrip cepat, tetapi untuk layanan jangka panjang ia menyediakan fondasi yang solid dan skalabel. Pendekatannya yang modern (dan pengembangan aktif) membuatnya menjadi pilihan yang progresif.
-
Bun ideal untuk pengembang yang mengatakan “saya tahu SQL dan saya hanya ingin bantuan ringan di sekitarnya.” Ia menghindari beberapa ajaib untuk memberi Anda kontrol dan kecepatan. Jika Anda membangun layanan yang sangat sensitif terhadap kinerja dan tidak takut untuk eksplisit dalam kode akses data Anda, Bun adalah opsi yang menarik. Ia juga merupakan titik tengah yang baik jika Anda sedang bermigrasi dari
database/sql
+sqlx
mentah dan ingin menambahkan struktur tanpa mengorbankan efisiensi terlalu banyak. Pertukaran adalah komunitas yang lebih kecil dan sedikit abstraksi tingkat tinggi – Anda akan menulis sedikit lebih banyak kode secara manual. Tapi seperti yang dikatakan dokumen Bun, ia tidak mengganggu Anda. Gunakan Bun ketika Anda ingin ORM yang terasa seperti menggunakan SQL secara langsung, terutama untuk proyek yang berfokus pada PostgreSQL di mana Anda dapat memanfaatkan fitur khusus database. -
sqlc berada dalam kategori tersendiri. Ia sempurna untuk tim Go yang mengatakan “kami tidak ingin ORM, kami ingin jaminan kompilasi untuk SQL kami.” Jika Anda memiliki keterampilan SQL yang kuat dan lebih suka mengelola query dan skema dalam SQL (mungkin Anda memiliki DBA atau hanya menikmati membuat SQL yang efisien), sqlc kemungkinan besar akan meningkatkan produktivitas dan kepercayaan Anda. Kinerja secara esensial optimal, karena tidak ada yang berada di antara query Anda dan database. Alasan satu-satunya untuk tidak menggunakan sqlc adalah jika Anda benar-benar tidak menyukai menulis SQL atau jika query Anda sangat dinamis hingga menulis banyak variasi menjadi beban. Bahkan dalam hal itu, Anda mungkin menggunakan sqlc untuk sebagian besar query statis dan menangani beberapa kasus dinamis dengan pendekatan lain. sqlc juga bermain baik dengan yang lain – ia tidak mengecualikan penggunaan ORM dalam bagian proyek Anda (beberapa proyek menggunakan GORM untuk hal sederhana dan sqlc untuk jalur kritis, misalnya). Singkatnya, pilih sqlc jika Anda menghargai eksplisitas, nol overhead, dan SQL yang aman tipe – ini adalah alat yang kuat untuk dimiliki.
Akhirnya, perlu dicatat bahwa alat-alat ini tidak saling eksklusif dalam ekosistem. Masing-masing memiliki kelebihan dan kekurangan, dan dalam semangat pragmatis Go, banyak tim mengevaluasi pertukaran secara kasus per kasus. Tidak tidak biasa untuk memulai dengan ORM seperti GORM atau Ent untuk kecepatan pengembangan, dan kemudian menggunakan sqlc atau Bun untuk jalur kritis yang membutuhkan kinerja maksimal. Semua empat solusi aktif dipelihara dan luas digunakan, jadi tidak ada pilihan “salah” secara keseluruhan – ini tentang pilihan yang tepat untuk konteks Anda. Semoga perbandingan ini memberi Anda gambaran yang lebih jelas tentang bagaimana GORM, Ent, Bun, dan sqlc berdiri, dan membantu Anda membuat keputusan yang terinformasi untuk proyek Go berikutnya Anda.
Tautan yang Berguna
- https://gorm.io
- https://entgo.io/
- https://bun.uptrace.dev
- https://github.com/sqlc-dev/sqlc
- https://blog.jetbrains.com/go/2023/04/27/comparing-db-packages/
- Golang Cheat Sheet
- Memperbaiki Kesalahan Golang GORM AutoMigrate PostgreSQL
- Mengurutkan ulang dokumen teks dengan Ollama dan model Qwen3 Embedding - dalam Go