在 Go 中连接到 Oracle DB
Connecting to Oracle DB in Go
我正在尝试从 Windows(64 位 Go,32 位客户端)
连接到 Oracle 数据库
我已经提交了 this 问题,但我是 Go 的新手,所以我对他建议的配置一无所知。
我安装了多个客户端,例如:
1. `code.google.com\p\odbc`
2. `github.com\mattn\go-oci8`
我试图创建 oci8.pc
文件,但它似乎是错误的。
prefix=/devel/target/1.0
exec_prefix=${prefix}
libdir=C:/oracle/instantclient_12_1/sdk/lib/msvc
includedir=C:/oracle/instantclient_12_1/sdk/include
oralib=C:/oracle/instantclient_12_1/sdk/lib/msvc
orainclude=C:/oracle/instantclient_12_1/sdk/include
gcclib=C:/TDM-GCC-64/lib
gccinclude=C:/TDM-GCC-64/include
glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums
Name: oci8
Version: 12.1
Description: oci8 library
Libs: -L${oralib} -L${gcclib} -loci
Libs.private:
Cflags: -I${orainclude} -I${gccinclude}
当我运行以下代码时,出现错误:
// TestDB
package main
import (
"github.com/odbc"
)
func main() {
conn, _ := odbc.Connect("DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXXX;PWD=XXXXX")
defer conn.Close()
stmt, _ := conn.Prepare("select * from XXXXX where XXXX = ?")
defer stmt.Close()
stmt.Execute("100044")
rows, _ := stmt.FetchAll()
for i, row := range rows {
println(i, row)
}
}
错误:
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x8 pc=0x43c3a6]
goroutine 1 [running]:
github.com/odbc.(*Connection).Close(0x0, 0x45)
C:/Go/UDL/src/github.com/odbc/odbc.go:263 +0x26
github.com/odbc.(*Connection).newStmt(0x0, 0x36, 0xc0820120e0)
C:/Go/UDL/src/github.com/odbc/odbc.go:152 +0x50
github.com/odbc.(*Connection).Prepare(0x0, 0x51cf70, 0x36, 0x0, 0x0, 0x0, 0xc082005e90, 0x9d6eb0)
C:/Go/UDL/src/github.com/odbc/odbc.go:162 +0x51
main.main()
C:/Go/My Codes/new/TestDB.go:12 +0xc4
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
我错过了什么吗?如果有人能指出我正确的方向,我将非常感激。
提前致谢。
编辑:
浏览更多后,我更改了我的代码如下:
// TestDB
package main
import (
_ "code.google.com/p/odbc"
"database/sql"
"fmt"
)
func main() {
fmt.Println(sql.Drivers())
db, err := sql.Open("odbc","DSN=lnxcepd1db01.xxxx.com:51521*CBPDEV;UID=XXXX;PWD=XXXX")
if err != nil {
panic(err)
}
rows, err := db.Query("select TABLE_NAME from tabs")
var TABLE_NAME string
defer rows.Close()
for rows.Next() {
fmt.Println(rows.Columns())
rows.Scan(&TABLE_NAME)
fmt.Println(TABLE_NAME)
}
err = rows.Err()
if err != nil {
panic(err)
}
defer db.Close()
}
输出+错误堆栈:
[odbc]
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x453408]
goroutine 1 [running]:
database/sql.(*Rows).Close(0x0, 0x0, 0x0)
c:/go/src/database/sql/sql.go:1659 +0x38
database/sql.(*Rows).Next(0x0, 0xc082002400)
c:/go/src/database/sql/sql.go:1586 +0x2c
main.main()
C:/Go/My Codes/new/TestDB.go:23 +0x263
goroutine 2 [runnable]:
runtime.forcegchelper()
c:/go/src/runtime/proc.go:90
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 3 [runnable]:
runtime.bgsweep()
c:/go/src/runtime/mgc0.go:82
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 4 [runnable]:
runtime.runfinq()
c:/go/src/runtime/malloc.go:712
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 5 [runnable]:
database/sql.(*DB).connectionOpener(0xc08205a000)
c:/go/src/database/sql/sql.go:588
created by database/sql.Open
c:/go/src/database/sql/sql.go:452 +0x323
如您所见,当我打印可用的驱动程序时,我得到 odbc
,我不确定我缺少什么。
我正在使用这个 odbc 驱动程序。
https://code.google.com/p/odbc/wiki/GettingStartedOnWindows
我注意到一件事:
当我使用
db, err := sql.Open("odbc", "DSN=lnxcepd1db01.XXXXX.com:51521;USERID=XXXX;PASSWORD=XXXX;DATABASE=CBPDEV")
我得到错误,
%v SQLDriverConnect: {IM002} [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified
当我尝试时,
db, err := sql.Open("odbc", "DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXX;PWD=XXXXX")
我收到错误:
SQLDriverConnect: {IM010} [Microsoft][ODBC Driver Manager] Data source name too long
还有这个:
db, err := sql.Open("odbc","DSN=lnxcepd1db01.XXXXX.com:51521*cbpdev;UID=XXX;PWD=XXXX")
错误:
SQLDriverConnect: {IM010} [Microsoft][ODBC Driver Manager] Data source name too long
我完全迷失了,因为我无法将此与驱动程序问题、代码问题或连接字符串中缺少的某些参数联系起来。
我有以下问题:
我的连接字符串有什么问题?
有没有人有从 API 大楼开始执行的工作设置或说明(很抱歉,但我尝试了一些但没有成功)?
哪个 API 更好用或更容易使用?
你得到的错误表明你正在尝试访问一个 "method" 一个未初始化的变量(nil 值)。
在使用返回的值之前,您应该检查没有错误。
package main
import (
"github.com/odbc"
"log"
)
func main() {
conn, err := odbc.Connect("DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXXX;PWD=XXXXX")
if err != nil {
log.Println(log)
return
}
defer conn.Close()
stmt, err := conn.Prepare("select * from XXXXX where XXXX = ?")
if err != nil {
log.Println(log)
return
}
defer stmt.Close()
stmt.Execute("100044")
rows, _ := stmt.FetchAll()
for i, row := range rows {
println(i, row)
}
}
这里有一个函数可以完成 conn/prep/query/fetch 操作:
func getDatePrepQuery(driver string, connString string) error {
db, err := sql.Open(driver, connString)
if err != nil {
log.Printf("sql.Open(%s, %s)\n\t%s\n",
driver, connString, err.Error())
return err
}
defer db.Close()
query := "select SYSDATE from dual"
stmt, err := db.Prepare(query)
if err != nil {
log.Printf("db.Prepare(%s) failed.\n\t%s\n", query, err.Error())
return err
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
log.Printf("stmt.Query() failed.\n\t%s\n", err.Error())
return err
}
defer rows.Close()
var columns []string
columns, err = rows.Columns()
if err != nil {
log.Printf("rows.Columns() failed.\n\t%s\n", err.Error())
}
for i, c := range columns {
fmt.Printf("%3d %s\n", i, c)
}
for rows.Next() {
var sysdate time.Time
err = rows.Scan(&sysdate)
if err != nil {
log.Printf("rows.Scan(...) failed.\n\t%s\n", err.Error())
return err
}
fmt.Println("SYSDATE:", sysdate)
}
err = rows.Err()
if err != nil {
log.Printf("rows iteration failed.\n\t%s\n", err.Error())
return err
}
return nil
}
使用 Scan 是一个棘手的部分,因为它可能不是 Oracle 程序员习惯的东西。此函数适用于我尝试过的所有 odbc、mgodbc、oci8、adodb 和 goracle 包。
它指向的研讨会和 repos,特别是 https://github.com/oracle/microservices-datadriven/tree/main/grabdish/inventory-go,可能会有帮助。
这是它的一个片段,显示了工作中的 src 和 dockerfile...
来源...
import (
"context"
"database/sql"
"github.com/godror/godror"
)
user := os.Getenv("DB_USER")
dbpassword := os.Getenv("DB_PASSWORD")
connectString := os.Getenv("DB_CONNECT_STRING") //for example "examplepdb_tp"
connectionString := user + "/" + dbpassword + "@" + connectString
connection, err := sql.Open("godror", connectionString)
Docker 文件...
FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
cp -r instantclient_19_3/* /lib && \
rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
apk add libaio && \
apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]
Dockerfile (including build)...
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git build-base
WORKDIR /src
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/inventory-go
FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
cp -r instantclient_19_3/* /lib && \
rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
apk add libaio && \
apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY --from=builder /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]
我正在尝试从 Windows(64 位 Go,32 位客户端)
连接到 Oracle 数据库我已经提交了 this 问题,但我是 Go 的新手,所以我对他建议的配置一无所知。
我安装了多个客户端,例如:
1. `code.google.com\p\odbc`
2. `github.com\mattn\go-oci8`
我试图创建 oci8.pc
文件,但它似乎是错误的。
prefix=/devel/target/1.0
exec_prefix=${prefix}
libdir=C:/oracle/instantclient_12_1/sdk/lib/msvc
includedir=C:/oracle/instantclient_12_1/sdk/include
oralib=C:/oracle/instantclient_12_1/sdk/lib/msvc
orainclude=C:/oracle/instantclient_12_1/sdk/include
gcclib=C:/TDM-GCC-64/lib
gccinclude=C:/TDM-GCC-64/include
glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums
Name: oci8
Version: 12.1
Description: oci8 library
Libs: -L${oralib} -L${gcclib} -loci
Libs.private:
Cflags: -I${orainclude} -I${gccinclude}
当我运行以下代码时,出现错误:
// TestDB
package main
import (
"github.com/odbc"
)
func main() {
conn, _ := odbc.Connect("DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXXX;PWD=XXXXX")
defer conn.Close()
stmt, _ := conn.Prepare("select * from XXXXX where XXXX = ?")
defer stmt.Close()
stmt.Execute("100044")
rows, _ := stmt.FetchAll()
for i, row := range rows {
println(i, row)
}
}
错误:
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x8 pc=0x43c3a6]
goroutine 1 [running]:
github.com/odbc.(*Connection).Close(0x0, 0x45)
C:/Go/UDL/src/github.com/odbc/odbc.go:263 +0x26
github.com/odbc.(*Connection).newStmt(0x0, 0x36, 0xc0820120e0)
C:/Go/UDL/src/github.com/odbc/odbc.go:152 +0x50
github.com/odbc.(*Connection).Prepare(0x0, 0x51cf70, 0x36, 0x0, 0x0, 0x0, 0xc082005e90, 0x9d6eb0)
C:/Go/UDL/src/github.com/odbc/odbc.go:162 +0x51
main.main()
C:/Go/My Codes/new/TestDB.go:12 +0xc4
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
我错过了什么吗?如果有人能指出我正确的方向,我将非常感激。
提前致谢。
编辑:
浏览更多后,我更改了我的代码如下:
// TestDB
package main
import (
_ "code.google.com/p/odbc"
"database/sql"
"fmt"
)
func main() {
fmt.Println(sql.Drivers())
db, err := sql.Open("odbc","DSN=lnxcepd1db01.xxxx.com:51521*CBPDEV;UID=XXXX;PWD=XXXX")
if err != nil {
panic(err)
}
rows, err := db.Query("select TABLE_NAME from tabs")
var TABLE_NAME string
defer rows.Close()
for rows.Next() {
fmt.Println(rows.Columns())
rows.Scan(&TABLE_NAME)
fmt.Println(TABLE_NAME)
}
err = rows.Err()
if err != nil {
panic(err)
}
defer db.Close()
}
输出+错误堆栈:
[odbc]
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x453408]
goroutine 1 [running]:
database/sql.(*Rows).Close(0x0, 0x0, 0x0)
c:/go/src/database/sql/sql.go:1659 +0x38
database/sql.(*Rows).Next(0x0, 0xc082002400)
c:/go/src/database/sql/sql.go:1586 +0x2c
main.main()
C:/Go/My Codes/new/TestDB.go:23 +0x263
goroutine 2 [runnable]:
runtime.forcegchelper()
c:/go/src/runtime/proc.go:90
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 3 [runnable]:
runtime.bgsweep()
c:/go/src/runtime/mgc0.go:82
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 4 [runnable]:
runtime.runfinq()
c:/go/src/runtime/malloc.go:712
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 5 [runnable]:
database/sql.(*DB).connectionOpener(0xc08205a000)
c:/go/src/database/sql/sql.go:588
created by database/sql.Open
c:/go/src/database/sql/sql.go:452 +0x323
如您所见,当我打印可用的驱动程序时,我得到 odbc
,我不确定我缺少什么。
我正在使用这个 odbc 驱动程序。
https://code.google.com/p/odbc/wiki/GettingStartedOnWindows
我注意到一件事:
当我使用
db, err := sql.Open("odbc", "DSN=lnxcepd1db01.XXXXX.com:51521;USERID=XXXX;PASSWORD=XXXX;DATABASE=CBPDEV")
我得到错误,
%v SQLDriverConnect: {IM002} [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified
当我尝试时,
db, err := sql.Open("odbc", "DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXX;PWD=XXXXX")
我收到错误:
SQLDriverConnect: {IM010} [Microsoft][ODBC Driver Manager] Data source name too long
还有这个:
db, err := sql.Open("odbc","DSN=lnxcepd1db01.XXXXX.com:51521*cbpdev;UID=XXX;PWD=XXXX")
错误:
SQLDriverConnect: {IM010} [Microsoft][ODBC Driver Manager] Data source name too long
我完全迷失了,因为我无法将此与驱动程序问题、代码问题或连接字符串中缺少的某些参数联系起来。
我有以下问题:
我的连接字符串有什么问题? 有没有人有从 API 大楼开始执行的工作设置或说明(很抱歉,但我尝试了一些但没有成功)? 哪个 API 更好用或更容易使用?
你得到的错误表明你正在尝试访问一个 "method" 一个未初始化的变量(nil 值)。 在使用返回的值之前,您应该检查没有错误。
package main
import (
"github.com/odbc"
"log"
)
func main() {
conn, err := odbc.Connect("DSN=lnxcepd1db01.XXXXXX.com:51521*CBPDEV;UID=XXXXX;PWD=XXXXX")
if err != nil {
log.Println(log)
return
}
defer conn.Close()
stmt, err := conn.Prepare("select * from XXXXX where XXXX = ?")
if err != nil {
log.Println(log)
return
}
defer stmt.Close()
stmt.Execute("100044")
rows, _ := stmt.FetchAll()
for i, row := range rows {
println(i, row)
}
}
这里有一个函数可以完成 conn/prep/query/fetch 操作:
func getDatePrepQuery(driver string, connString string) error {
db, err := sql.Open(driver, connString)
if err != nil {
log.Printf("sql.Open(%s, %s)\n\t%s\n",
driver, connString, err.Error())
return err
}
defer db.Close()
query := "select SYSDATE from dual"
stmt, err := db.Prepare(query)
if err != nil {
log.Printf("db.Prepare(%s) failed.\n\t%s\n", query, err.Error())
return err
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
log.Printf("stmt.Query() failed.\n\t%s\n", err.Error())
return err
}
defer rows.Close()
var columns []string
columns, err = rows.Columns()
if err != nil {
log.Printf("rows.Columns() failed.\n\t%s\n", err.Error())
}
for i, c := range columns {
fmt.Printf("%3d %s\n", i, c)
}
for rows.Next() {
var sysdate time.Time
err = rows.Scan(&sysdate)
if err != nil {
log.Printf("rows.Scan(...) failed.\n\t%s\n", err.Error())
return err
}
fmt.Println("SYSDATE:", sysdate)
}
err = rows.Err()
if err != nil {
log.Printf("rows iteration failed.\n\t%s\n", err.Error())
return err
}
return nil
}
使用 Scan 是一个棘手的部分,因为它可能不是 Oracle 程序员习惯的东西。此函数适用于我尝试过的所有 odbc、mgodbc、oci8、adodb 和 goracle 包。
它指向的研讨会和 repos,特别是 https://github.com/oracle/microservices-datadriven/tree/main/grabdish/inventory-go,可能会有帮助。
这是它的一个片段,显示了工作中的 src 和 dockerfile...
来源...
import (
"context"
"database/sql"
"github.com/godror/godror"
)
user := os.Getenv("DB_USER")
dbpassword := os.Getenv("DB_PASSWORD")
connectString := os.Getenv("DB_CONNECT_STRING") //for example "examplepdb_tp"
connectionString := user + "/" + dbpassword + "@" + connectString
connection, err := sql.Open("godror", connectionString)
Docker 文件...
FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
cp -r instantclient_19_3/* /lib && \
rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
apk add libaio && \
apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]
Dockerfile (including build)...
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git build-base
WORKDIR /src
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/inventory-go
FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
cp -r instantclient_19_3/* /lib && \
rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
apk add libaio && \
apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY --from=builder /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]