本文在 Windows 7 64bit 系统上使用 golang 连接查询 oracle 数据库。
环境准备
前置条件:
安装mingw(取其gcc及库,因为要用cgo编译),安装git(取其bash)。安装oci。
oracle提供了编程接口,golang 有多个实现库,但均需依赖 oracle 的 instantclient。下载OCI:
https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html 。
版本有 SDK 版本、Basic 版本。压缩包虽不同,但内含目录一致,解压到当前目录即可,拷贝到指定目录,示例:D:\oracle\instantclient
。
PKG_CONFIG_PATH环境变量 (失败)
1 | D:\mingw64\lib\pkg-config |
执行echo $PKG_CONFIG_PATH
查看目录,映射到 E:\Program Files\Git\mingw64\lib 下,不存在pkgconfig,创建之。
注:本文使用 go-oci8,似乎只支持 oci 12 版本。过高版本运行时初始化失败。
安装库
1、
获取oci8.pc。执行:
1 | go get github.com/wendal/go-oci8 |
无须理会错误,此处是下载源码,主要获取pkg-config.exe和oci8.pc文件。在下载包go-oci8的windows目录(位于$GOPATH\src\github.com\wendal\go-oci8\windows),将pkg-config.exe拷贝到 $PATH 目录,oci8.pc拷贝到 $PKG_CONFIG_PATH 目录。
注:如果系统已有pkg-config.exe,则不需拷贝。
注:$PKG_CONFIG_PATH如果没有指定,则设置环境变量。笔者使用的 git bash 已设置好,如下:
1 | echo $PKG_CONFIG_PATH |
2、
再次执行:
1 | go get github.com/wendal/go-oci8 |
一说:把oci8.pc文件的lclntsh改为oci,修改后,再执行,通过。得到pkg\windows_amd64\github.com\wendal\go-oci8.a
目录。
由作者说明得知,wendal
是从mattn
仓库fork得到的,也下载:
1 | go get github.com/mattn/go-oci8 |
对比两者源码和生成的.a文件,mattn的文件也多,库也比较大。但对比使用者而言无区别。为安全起见,实际工程使用 mattn 库。
3、
修改后的oci8.pc文件内容如下:
1 | prefix=D:/oracle/instantclient |
注:前面的变量一定使用全路径,不使用${prefix}
,另外要将库修改为oci。
4、
编写测试代码。go build 出错:
1 | # command-line-arguments |
猜想:官方oci是.lib格式,gcc不认。而golang的驱动得到.a但没有包括oci里面的函数。将得到的go-oci8.a改名为liboci.a,再次go build
,提示未定义的函数,用nm
查之,函数前为U
,猜测格式不对。
1 | $ pkg-config --cflags -- oci8 |
在D:\oracle\instantclient
目录找oci.dll,放到临时目录。从dll生成.a。
1 | $ gendef.exe oci.dll # 注:从dll生产def(下一步要用到) |
生成的文件为liboci.a,可用nm
查函数,已有定义。将其放到D:\oracle\instantclient\sdk\lib\msvc
目录(注:也可以是其它目录)。
5、
疑惑1:
似乎golang生成的go-oci8.a没什么用,可能内部链接了里面的函数,但最终的oci函数,还是从官方的oci库中获取,如OCIStmtPrepare。
疑惑2:
在go get github.com/mattn/go-oci8
处,会使用pc文件指定的参数,但似乎只针对头文件,也没有链接,具体未详细研究(因为.lib和.a格式已然不同,不通用,链接不上的,没报错,应该没链接)。
疑惑3:
在测试中发现,如果编译成功后,将 D:\mingw64\lib\liboci.a 改后缀名,也会编译通过(猜测应该是 Golang 做了库的缓存,暂无时间研究透)。
疑惑4:
在编译 Golang 的机器上连接 oracle 一切正常,将可执行文件放到另一台安装了 oci 的电脑上,提示初始化失败,经查,未找到原因。
解决:经查,是 oci 版本导致的。使用 ProcessExplorer 查看其依赖的 oci 库,发现有 oraociei12.dll oraons.dll oci.dll 三个,另一电脑的 oci 为 19 版本,拷贝正确的,可运行。
疑惑5:
编译后应该有个库什么的,名称是什么?在哪里?
6、关于pc文件的说明
操作:修改oci8.pc文件,再用go build -x github.com/mattn/go-oci8
编译。
如果使用Windows风格的分隔符’',如D:\oracle\instantclient\sdk\lib\msvc,解析的结果变成”-LD:oracleinstantclientsdklibmsvc”,错误。
如果使用宏,如libdir=${prefix}/sdk/include,${prefix}不能正确解析,路径错误。
本文正确示例为:
1 | CGO_LDFLAGS='"-g" "-O2" "-LD:/oracle/instantclient/sdk/lib/msvc" "-loci"' "D:\\go\\pkg\\tool\\windows_amd64\\cgo.exe" -objdir "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\go-build339110594\\b001\\" -importpath github.com/mattn/go-oci8 -- -ID:/oracle/instantclient/sdk/include .... |
源码
1 | package main |
参考资料
参考资料:
https://www.cnblogs.com/good-temper/p/3791874.html
https://blog.csdn.net/yh_coco/article/details/78068610