Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Driver go-mssqldb mendukung pemanggilan prosedur tersimpan dengan parameter input, parameter output, dan nilai status pengembalian. Artikel ini membahas pola umum.
Sebagian besar cuplikan dalam artikel ini menganggap penyiapan database/sql yang umum sudah tersedia, dengan database/sql diimpor sebagai sql, nilai ctx tersedia, dan db telah diinisialisasi. Cuplikan menyertakan blok import hanya jika menambahkan paket tambahan seperti context, fmt, log, os, atau github.com/microsoft/go-mssqldb. Ketika blok kode dengan sengaja melanjutkan contoh yang sama, gunakan = untuk nilai yang telah dideklarasikan sebelumnya dalam contoh tersebut; gunakan := untuk deklarasi baru dalam cuplikan mandiri.
Panggil prosedur tersimpan
Gunakan ExecContext atau QueryContext dengan nama prosedur secara langsung:
_, err := db.ExecContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6))
Lebih suka nama prosedur ditambah parameter untuk panggilan prosedur biasa. Gunakan string eksplisit EXECUTE ... hanya ketika Anda perlu menyematkan panggilan dalam batch Transact-SQL (T-SQL) yang lebih besar atau menggunakan sintaks yang tidak diwakili oleh sql.Named parameter.
Parameter output
Gunakan sql.Named dengan sql.Out untuk menerima nilai parameter output:
import (
"context"
"database/sql"
"fmt"
"log"
)
ctx := context.Background()
var employeeCount int64
_, err := db.ExecContext(ctx, "dbo.GetEmployeeCount",
sql.Named("count", sql.Out{Dest: &employeeCount}))
if err != nil {
log.Fatal(err)
}
fmt.Println("Employee count:", employeeCount)
Prosedur T-SQL yang sesuai:
CREATE PROCEDURE dbo.GetEmployeeCount
@count INT OUTPUT
AS
BEGIN
SELECT @count = COUNT(*) FROM HumanResources.Employee;
END;
Parameter masukan/keluaran
Untuk parameter yang merupakan input dan output, atur In: true pada sql.Out struktur:
var result int64 = 10
_, err := db.ExecContext(ctx, "dbo.DoubleValue",
sql.Named("value", sql.Out{Dest: &result, In: true}))
if err != nil {
log.Fatal(err)
}
fmt.Println("Doubled:", result)
Status pengembalian
Gunakan mssql.ReturnStatus untuk menangkap nilai pengembalian bilangan bulat dari prosedur yang disimpan. Contoh ini menggunakan prosedur AdventureWorks dbo.uspGetEmployeeManagers :
import (
"database/sql"
"fmt"
"log"
mssql "github.com/microsoft/go-mssqldb"
)
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Println("Return status:", returnStatus)
ReturnStatus bekerja dengan ExecContext dan QueryContext, tetapi tidak dengan QueryRowContext.
Anda dapat menggabungkan ReturnStatus dengan parameter prosedur. Contoh ini melanjutkan contoh sebelumnya, sehingga menggunakan kembali impor mssql yang ditunjukkan sebelumnya dan menggunakan prosedur AdventureWorks dbo.uspGetEmployeeManagers:
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
Kumpulan hasil dari prosedur tersimpan
Jika prosedur tersimpan mengembalikan kumpulan hasil, gunakan QueryContext:
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers", sql.Named("BusinessEntityID", 6))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var reportingLevel int
var employeeID int
var employeeFirstName string
var employeeLastName string
var organizationNode string
var managerFirstName string
var managerLastName string
if err := rows.Scan(&reportingLevel, &employeeID, &employeeFirstName, &employeeLastName, &organizationNode, &managerFirstName, &managerLastName); err != nil {
log.Fatal(err)
}
fmt.Printf("Level %d: %d %s %s (manager: %s %s)\n",
reportingLevel, employeeID, employeeFirstName, employeeLastName, managerFirstName, managerLastName)
_ = organizationNode
}
Untuk prosedur yang mengembalikan beberapa set hasil, gunakan rows.NextResultSet(). Untuk informasi selengkapnya, lihat Kueri dan pernyataan.
Baca semua baris sebelum menggunakan parameter output atau status pengembalian
SQL Server mengirimkan parameter output dan mengembalikan nilai status setelah kumpulan hasil selesai. Jika Anda membaca variabel output sebelum menggunakan semua baris, nilainya masih bisa tidak lengkap.
Contoh ini melanjutkan contoh sebelumnya dan menggunakan kembali impor mssql yang ditampilkan sebelumnya.
Itu tidak mencetak data baris. Perulangan hanya menggunakan kumpulan hasil sehingga returnStatus tersedia setelah kueri selesai.
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var reportingLevel int
var employeeID int
var employeeFirstName string
var employeeLastName string
var organizationNode string
var managerFirstName string
var managerLastName string
if err := rows.Scan(&reportingLevel, &employeeID, &employeeFirstName, &employeeLastName, &organizationNode, &managerFirstName, &managerLastName); err != nil {
log.Fatal(err)
}
_ = organizationNode
_ = managerFirstName
_ = managerLastName
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Println("Return status:", returnStatus)
Gunakan ExecContext saat prosedur tidak mengembalikan baris. Jika prosedur memang mengembalikan baris data, tunggu hingga semua baris dan set hasil selesai diproses sebelum Anda membaca parameter output atau status pengembalian.
Tabel sementara dan prosedur tersimpan
Saat Anda membuat tabel sementara dan kemudian mengkuerinya dalam panggilan terpisah, operasi mungkin berjalan pada koneksi yang berbeda dari kumpulan. Karena tabel sementara hanya berlaku dalam satu koneksi, pemanggilan kedua mungkin tidak dapat melihat tabel tersebut.
Untuk bekerja dengan tabel sementara, gunakan pendekatan koneksi tunggal:
conn, err := db.Conn(ctx)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.ExecContext(ctx, "CREATE TABLE #TempItems (Id INT, Name NVARCHAR(50))")
if err != nil {
log.Fatal(err)
}
_, err = conn.ExecContext(ctx, "INSERT INTO #TempItems VALUES (1, N'Item A')")
if err != nil {
log.Fatal(err)
}
rows, err := conn.QueryContext(ctx, "SELECT * FROM #TempItems")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
Atau, jalankan operasi tersebut dalam sebuah transaksi, yang secara otomatis mengikatnya ke koneksi yang sama.
Tangkap pesan PRINT dan RAISERROR
Pernyataan SQL Server PRINT dan RAISERROR dengan tingkat keparahan 0-10 menghasilkan pesan informasi yang tidak dikembalikan sebagai kesalahan Go. Untuk menangkap pesan ini, aktifkan log parameter koneksi dengan bendera 2 (pesan):
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=2
Dengan logging diaktifkan, driver menulis output dan pesan PRINT dengan tingkat keparahan rendah ke paket RAISERROR standar Go. Untuk menangkapnya secara terprogram, atur logger kustom sebelum membuka koneksi:
import (
"database/sql"
"log"
"os"
mssql "github.com/microsoft/go-mssqldb"
)
// Direct driver messages to a custom logger.
mssql.SetLogger(log.New(os.Stdout, "mssql: ", log.LstdFlags))
db, err := sql.Open("sqlserver",
"sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=2")
Kemudian prosedur tersimpan apa pun yang menggunakan PRINT atau RAISERROR(..., 0, 1) mengirim pesannya ke logger Anda.
Note
RAISERROR dengan tingkat keparahan 11 atau lebih tinggi menghasilkan kesalahan Go yang dapat Anda tangani dengan pemeriksaan kesalahan normal. Hanya pesan tingkat keparahan 0-10 yang memerlukan log parameter untuk menangkap.
Untuk informasi selengkapnya tentang bendera pengelogan dan pengambilan log terprogram, lihat Pengelogan dan diagnostik.