golang高性能Oracle数据库驱动插件库godror的使用
golang高性能Oracle数据库驱动插件库godror的使用
概述
godror是一个用于连接Oracle数据库的database/sql/driver.Driver实现,它使用了Anthony Tuininga的优秀OCI包装器ODPI-C。
构建要求
- Go 1.15或更高版本
- 启用了CGO的C编译器(CGO_ENABLED=1),因此跨平台编译较困难
运行时要求
- Oracle客户端库 - 请参考ODPI-C的安装文档
虽然编译时不需要Oracle客户端库,但在运行时是必需的。可以从Oracle官网下载免费的Basic或Basic Light包。
安装
运行以下命令安装godror:
go get github.com/godror/godror@latest
然后安装Oracle客户端库即可使用。
连接Oracle数据库
使用sql.Open("godror", dataSourceName)
连接Oracle数据库,其中dataSourceName
是一个logfmt编码的参数列表。至少需要指定"user"、"password"和"connectString"参数。例如:
db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)
connectString
可以是SQL*Plus或Oracle Call Interface(OCI)接受的任何内容:服务名、Easy Connect字符串如host:port/service_name
,或连接描述符如(DESCRIPTION=...)
。
可以通过"?connect_timeout=15"指定连接超时秒数(注意connect_timeout需要至少19c客户端)。
连接池
Oracle的OCI客户端(godror底层使用)在快速连接-重连循环中存在问题,可能导致C库中的SIGSEGV。因此请使用某种连接池 - 可以是db.SetMaxIdleConns设置大于0的值,或使用驱动内置的会话池(standaloneConnection=0, poolMinSessions=1)。
完整示例
以下是一个完整的godror使用示例:
package main
import (
"context"
"database/sql"
"fmt"
"log"
"time"
_ "github.com/godror/godror"
)
func main() {
// 连接Oracle数据库
db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 设置连接池参数
db.SetMaxIdleConns(5)
db.SetMaxOpenConns(10)
db.SetConnMaxLifetime(time.Minute * 5)
// 检查连接
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
log.Fatal(err)
}
// 查询示例
rows, err := db.QueryContext(ctx, "SELECT empno, ename FROM emp WHERE deptno = :1", 10)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var empno int
var ename string
if err := rows.Scan(&empno, &ename); err != nil {
log.Fatal(err)
}
fmt.Printf("Employee %d: %s\n", empno, ename)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
// 调用存储过程示例(返回游标)
var rset driver.Rows
const query = `BEGIN Package.StoredProcA(123, :1); END;`
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
if _, err := stmt.ExecContext(ctx, sql.Out{Dest: &rset}); err != nil {
log.Fatal(err)
}
defer rset.Close()
// 处理返回的游标数据
cols := rset.(driver.RowsColumnTypeScanType).Columns()
dests := make([]driver.Value, len(cols))
for {
if err := rset.Next(dests); err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
fmt.Println(dests)
}
}
注意事项
-
sql.NullString:不支持,因为Oracle DB不区分空字符串("")和NULL
-
NUMBER类型:作为字符串传输到Go底层,确保不丢失精度
-
CLOB/BLOB:从2.9.0开始,默认返回为string/[]byte
-
TIMESTAMP:所有time.Time都绑定为DATE,因此会丢失小数秒
-
时区:默认使用数据库OS的时区
-
上下文超时:始终尽快关闭sql.Rows
贡献
与其他Go项目一样,你不需要更改导入路径,但可以在本地修改库代码。设置不同的远程仓库后即可提交Pull Request。
第三方工具
- oracall:生成用于调用存储过程的服务器
更多关于golang高性能Oracle数据库驱动插件库godror的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高性能Oracle数据库驱动插件库godror的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
godror - Golang高性能Oracle数据库驱动使用指南
godror是Oracle官方推荐的Go语言Oracle数据库驱动,基于Oracle的ODPI-C接口实现,具有高性能和稳定性。下面详细介绍其使用方法。
安装
go get github.com/godror/godror
需要先安装Oracle客户端库,并设置相关环境变量:
- 下载Oracle Instant Client Basic或Basic Light包
- 解压并设置LD_LIBRARY_PATH(linux)或PATH(windows)
基本使用
连接数据库
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/godror/godror"
)
func main() {
// 连接字符串格式: user/pass@host:port/service_name
dsn := "scott/tiger@localhost:1521/ORCLPDB1?connect_timeout=30"
db, err := sql.Open("godror", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 测试连接
err = db.Ping()
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to Oracle database successfully!")
}
查询数据
func queryData(db *sql.DB) {
rows, err := db.Query("SELECT employee_id, first_name, last_name FROM employees WHERE department_id = :1", 50)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var (
id int
firstName string
lastName string
)
if err := rows.Scan(&id, &firstName, &lastName); err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Name: %s %s\n", id, firstName, lastName)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}
执行DML操作
func insertData(db *sql.DB) {
result, err := db.Exec(
"INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, job_id) "+
"VALUES (:1, :2, :3, :4, :5, :6)",
207, "John", "Doe", "JDOE", time.Now(), "IT_PROG")
if err != nil {
log.Fatal(err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted %d row(s)\n", rowsAffected)
}
高级特性
批量插入
func batchInsert(db *sql.DB) {
// 准备语句
stmt, err := db.Prepare("INSERT INTO employees (employee_id, first_name, last_name) VALUES (:1, :2, :3)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
// 批量插入
for i := 0; i < 10; i++ {
_, err = stmt.Exec(300+i, fmt.Sprintf("First%d", i), fmt.Sprintf("Last%d", i))
if err != nil {
log.Fatal(err)
}
}
}
事务处理
func transactionExample(db *sql.DB) {
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// 执行事务操作
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE account_id = 1")
if err != nil {
tx.Rollback()
log.Fatal(err)
}
_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE account_id = 2")
if err != nil {
tx.Rollback()
log.Fatal(err)
}
err = tx.Commit()
if err != nil {
log.Fatal(err)
}
fmt.Println("Transaction completed successfully")
}
使用Oracle特有类型
func oracleTypesExample(db *sql.DB) {
var (
id int
name string
hireDate time.Time
salary float64
photo []byte
)
err := db.QueryRow(`
SELECT employee_id, first_name, hire_date, salary, photo
FROM employees
WHERE employee_id = :1`, 100).Scan(&id, &name, &hireDate, &salary, &photo)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Name: %s, Hire Date: %v, Salary: %.2f, Photo Size: %d\n",
id, name, hireDate, salary, len(photo))
}
性能优化技巧
- 连接池配置:
db.SetMaxOpenConns(25) // 最大连接数
db.SetMaxIdleConns(5) // 最大空闲连接数
db.SetConnMaxLifetime(time.Hour) // 连接最大存活时间
-
使用预编译语句:重复执行的SQL应使用Prepare
-
批量操作:使用数组绑定提高批量操作性能
-
适当设置fetch size:
rows, err := db.Query("SELECT /*+ godror.fetchSize=100 */ * FROM large_table")
- 使用连接上下文:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
rows, err := db.QueryContext(ctx, "SELECT * FROM slow_query")
常见问题解决
-
ORA-12545: Connect failed because target host or object does not exist
- 检查连接字符串格式
- 确认Oracle监听服务运行正常
-
ORA-01017: invalid username/password; logon denied
- 检查用户名密码
- 确认用户有连接权限
-
DPI-1047: Oracle Client library cannot be loaded
- 确认Oracle Instant Client已安装
- 检查环境变量设置
godror提供了高性能的Oracle数据库访问能力,通过合理配置和使用其高级特性,可以满足企业级应用的需求。更多详细配置和选项请参考官方文档。