我有一个带有A_LOB_TABLE表的数据库:

oracle - 如何将镜像作为BLOB插入Oracle数据库-LMLPHP

我想使用goracle包将具有任何(假设为“1”)ID的BLOB图像插入A_LOB_TABLE。

这是我的代码:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// To have a valid LOB locator, we have to keep the Stmt around.
qry := `DECLARE tmp BLOB;
BEGIN
  DBMS_LOB.createtemporary(tmp, TRUE, DBMS_LOB.SESSION);
  :1 := tmp;
END;`
    tx, err := testDb.BeginTx(ctx, nil)
    if err != nil {
        fmt.Println(err)
    }
    defer tx.Rollback()

stmt, err := tx.PrepareContext(ctx, qry)
if err != nil {
    fmt.Printf("%s: %w", qry, err)
}
defer stmt.Close()
var tmp goracle.Lob
if _, err := stmt.ExecContext(ctx, goracle.LobAsReader(), sql.Out{Dest: &tmp}); err != nil {
    fmt.Printf("Failed to create temporary lob: %+v", err)
}
fmt.Printf("tmp: %#v", tmp)

// Get file as bytes (it needs to be in the same dir as code is)
dat, err := ioutil.ReadFile("./sample.png")
if err != nil {
    fmt.Println(".....Error Opening File")
    fmt.Println(err)
    return
}

if _, err := tx.ExecContext(ctx,
    "BEGIN dbms_lob.append(:1, :2); END;",
    tmp, goracle.Lob{Reader: bytes.NewReader(dat[:])},
); err != nil {
    fmt.Printf("Failed to write buffer(%v) to lob(%v): %+v", dat, tmp, err)
}

// INSERTING LOB - starting....
_, err = testDb.Exec("insert into A_LOB_TABLE(id, image) VALUES(:1, :2)",  1, tmp)
if err != nil {
    fmt.Println(".....Error Inserting data - BLOB")
    fmt.Println(err)
    return
}
// INSERTING LOB - ended.

它不起作用。在行输出错误
_, err = testDb.Exec("insert into A_LOB_TABLE(id, image) VALUES(:1, :2)",  1, tmp)

说:

最佳答案

经过数十个小时的尝试,试图弄清楚如何使用goracle Go驱动程序将BLOB插入OracleDB中后,我得到了答案。

TL; DR

完整代码(显然可以根据需要调整变量,例如数据库连接和文件位置&&文件名):

package main

import (
    "bytes"
    "context"
    "database/sql"
    "fmt"
    "io/ioutil"
    "time"
goracle "gopkg.in/goracle.v2"
)

func main() {
    fmt.Println("... Setting up Database Connection")
    testDb, err := sql.Open("goracle",
        "sys" +
            "/" +
            "Oracle18" +
            "@" +
            "localhost:32118" +
            "/" +
            "XE as sysdba")
    if err != nil {
        fmt.Println("... DB Setup Failed")
        fmt.Println(err)
        return
    }
    defer testDb.Close()

// Get file as bytes
dat, err := ioutil.ReadFile("./sample.png")
if err != nil {
    fmt.Println(".....Error Opening File")
    fmt.Println(err)
    return
}

// BLOB creation && passing file into it
directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

fmt.Println("\nINSERTING BLOB - starting....")
// Working BLOB insertion - INSERT COMMAND
_, err = testDb.Exec("insert into AA_LIVE_FRAMES(id, frame) VALUES(:1, :2)",  1, directLob)
if err != nil {
    fmt.Println(".....Error Inserting BLOB")
    fmt.Println(err)
    return
}
fmt.Println("\nINSERTING BLOB - ended.")

fmt.Println("\nSuccess")
}

这是main.go文件。

更长的版本

如果代码是如此简单,为什么要花这么长时间呢?

当我开始解决该问题时,我没有在goracle文档中找到任何教程或示例来说明如何将BLOB插入OracleDB。当然,有一个功能不错的goracle.Lob结构-Read()。这是我的第一次尝试,声明此goracle.Lob并使用它的Read()函数,但它给了我错误-零地址等。我不知道为什么,尝试调试它-没有结果。然后,我进行了更深入的研究,从goracle软件包中提取了一些测试代码,这些代码显示了如何创建临时LOB-这些代码中的一些显示在我的问题答案中。再次,没有成功。然后,我尝试使用原始SQL,再次失败(我认为是因为我的OracleDB是docker-创建目录,将BLOB插入OracleDB所需的目录不起作用; nvm)。

最后,我不确定为什么,我尝试了structliteral:
directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

和工作。

好吧,为什么我要输入所有这些?因为,AFAIK,这样做:
directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

还有这个:
directLob := goracle.Lob{}
directLob.Read(dat[:])

应该一样吗?还是我完全错了?

10-06 08:41