【问题标题】:Connecting to Oracle DB in Go在 Go 中连接到 Oracle 数据库
【发布时间】:2021-09-30 22:56:55
【问题描述】:

我正在尝试从 Windows(64 位 Go,32 位客户端)连接到 Oracle DB

我已经提交了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 更好或更容易使用?

【问题讨论】:

  • 您的程序无法编译。没有名为“github.com/odbc”的包。请显示您的程序的来源。
  • 我正在尝试编译你的代码,你得到了哪些包?
  • 检查你的错误而不是忽略它们。他们告诉你什么?
  • @MIkCode 我编辑了帖子。请检查一下。
  • @ADi 它看起来像第 23 行,我在假设 rows 为 nil 时引发恐慌,你能检查 rows 是否为 nil 吗?

标签: windows oracle go odbc


【解决方案1】:

这里有一个函数来完成一个完整的 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 软件包。

【讨论】:

  • 如果您也可以更正我的连接字符串格式,那就太好了!谢谢:)
  • 与任何 Go sql 驱动程序一起使用的连接字符串没有什么特别之处。如果您可以在控制面板 ODBC 工具中配置 DSN,请使用:connString := fmt.Sprintf("DSN=%s;UID=%s;PWD=%s", dsn, user, password) 否则 connString = fmt.Sprintf("Driver={%s};SERVER=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d))(CONNECT_DATA=(SERVICE_NAME=%s)));uid=%s;pwd=%s;", driver, hostname, port, service_name, user, password)BUT 始终检查错误状态,以便了解哪个函数出错以及错误是什么。如果 conn 字符串错误,这将是一个 ODBC 错误消息。谷歌那个。
  • 感谢一个例子conn/prep/query/fetch 是完美的顺序,你也可以添加重新连接到FOR / ERR to CONTINUE / BREAK :D
【解决方案2】:

您得到的错误表明您正在尝试访问未初始化变量(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)
    }

}

【讨论】:

    【解决方案3】:

    本博客:https://blogs.oracle.com/developers/developing-microservices-in-java%2c-javascript%2c-python%2c-net%2c-and-go-with-the-oracle-converged-database

    它指向的研讨会和存储库,特别是https://github.com/oracle/microservices-datadriven/tree/main/grabdish/inventory-go,可能会有所帮助。

    这里有一个 sn-p 显示工作的 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)
    

    Dockerfile...

    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"]
    

    【讨论】:

      猜你喜欢
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      • 1970-01-01
      相关资源
      最近更新 更多