使用goracle包向Oracle的A_LOB_TABLE插入BLOB图片报错ORA-22922
解决goracle插入BLOB时ORA-22922错误的方案
你遇到的ORA-22922: nonexistent LOB value错误,核心原因是临时LOB的生命周期和事务不匹配,咱们一步步拆解问题,再给你两个可行的解决办法:
问题根源
- 你在事务
tx里创建了临时LOB,但插入操作却用了testDb.Exec——这相当于开启了一个全新的独立事务,原来事务里的LOB定位器在这个新事务里已经失效了。 - 而且你还
defer tx.Rollback(),就算你改用tx.Exec插入,最后回滚事务也会把临时LOB直接销毁,导致插入失败。
方案一:直接插入字节数组(推荐,更简洁)
goracle其实支持直接将字节数组作为BLOB参数传入,不需要手动创建临时LOB,代码会简化很多:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // 读取图片文件 dat, err := ioutil.ReadFile("./sample.png") if err != nil { fmt.Println(".....Error Opening File") fmt.Println(err) return } // 开启事务执行插入(也可根据需求去掉事务) tx, err := testDb.BeginTx(ctx, nil) if err != nil { fmt.Println(err) return } defer func() { if r := recover(); r != nil { tx.Rollback() } }() _, err = tx.ExecContext(ctx, "insert into A_LOB_TABLE(id, image) VALUES(:1, :2)", 1, dat) if err != nil { fmt.Println(".....Error Inserting data - BLOB") fmt.Println(err) tx.Rollback() return } // 提交事务保存数据 if err := tx.Commit(); err != nil { fmt.Println("Failed to commit transaction:", err) tx.Rollback() return } fmt.Println("Image inserted successfully!")
方案二:修正临时LOB的事务逻辑
如果你一定要用临时LOB的方式,需要保证所有操作(创建LOB、写入数据、插入表)都在同一个事务里,并且最后提交事务而不是回滚:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() tx, err := testDb.BeginTx(ctx, nil) if err != nil { fmt.Println(err) return } defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 创建临时LOB(会话级) qry := `DECLARE tmp BLOB; BEGIN DBMS_LOB.createtemporary(tmp, TRUE, DBMS_LOB.SESSION); :1 := tmp; END;` stmt, err := tx.PrepareContext(ctx, qry) if err != nil { fmt.Printf("%s: %w", qry, err) tx.Rollback() return } 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) tx.Rollback() return } // 读取图片文件 dat, err := ioutil.ReadFile("./sample.png") if err != nil { fmt.Println(".....Error Opening File") fmt.Println(err) tx.Rollback() return } // 写入数据到临时LOB 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 to lob: %+v", err) tx.Rollback() return } // 在同一个事务里执行插入 _, err = tx.ExecContext(ctx, "insert into A_LOB_TABLE(id, image) VALUES(:1, :2)", 1, tmp) if err != nil { fmt.Println(".....Error Inserting data - BLOB") fmt.Println(err) tx.Rollback() return } // 提交事务,保存数据和LOB if err := tx.Commit(); err != nil { fmt.Println("Failed to commit transaction:", err) tx.Rollback() return } fmt.Println("Image inserted successfully using temporary LOB!")
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

