0%

使用 golang 连接 Oracle (Windows 篇)

最近在使用 golang 进行项目开发,而公司的主要数据库还是 Oracle ,在尝试 golang 连接 Oracle 上着实碰到了钉子,没想到都 9102 年快结束了 oracle 依然没有提供 golang 的驱动,目前现有的库只能基于 oci8 来调用,而大部分对 Windows 上进行开发都不怎么友好(毕竟要交叉编译),我选择的是 go-oci8 ,开发机器是 Windows10 64 位,当中的过程在这里小小的分享一下。

安装 MinGW64

因为 go-oci8 中用到了 cgo 调用,因此需要配置 gcc 环境,一般在 Linux 下可以跳过该步骤或者用包管理直接安装了,Windows 下则需要自行寻找安装。这里我选择的是 MinGW ,同时由于我的是 64 位的主机,因此需要的是 MinGW64 的环境来编译。 MinGW64 的下载可以到 sourceforge 上下载,这里选择的是 x86_64-posix-seh 。解压缩之后得到 mingw64 文件夹,将其放置在英文路径下(我这里选择的是 E 盘下的 MinGW 目录,所以路径为 E:\MinGW\mingw64 )。

版本选项说明

  1. Version 指定版本号,从4.9.1-8.1.0,按需选择,没有特殊要求就用最新版吧;
  2. Architecture 跟操作系统有关,64位系统选择 x86_64 ,32位系统选择 i686;
  3. Threads 设置线程标准可选 posix 或 win32 ;
  4. Exception 设置异常处理系统,x86_64可选为seh和sjlj,i686为dwarf和sjlj;
  5. Build revision 构建版本号,选择最大即可。

然后将其 bin 目录添加到环境变量 PATH 中,然后在命令行中运行 gcc -v ,得到 gcc 版本信息即安装无误。

下载 OCI 以及 OCI SDK

instantclient 以及其 SDK 均可以在 Oracle 的下载网站上找到(这个确实比以前方便很多,遥想之前下个驱动还要登 Oracle 账号 ( ゚∀。)),根据主机的系统选择下载链接(比如 Window10 64位就是 Instant Client for Microsoft Windows (x64)),然后选择 Basic Package 和 SDK Package 下载。解压缩之后得到 instantclient_19_3 文件夹,同样是放置在英文路径下(我这里选择 E 盘下,所以路径位 E:\instantclient_19_3

然后将 instantclient_19_3 的路径添加到环境变量 PATH 上。

安装 pkg-config

pkg-config 是一个 Linux 下的编译工具,这里折腾了好久也没有找到 Windows 编译好的二进制格式(好吧你们可以哈我了 ( ´_ゝ`)),没关系,反正有 GCC ,又进入了传统的“我编译我自己”的环节了。

这里先下载 pkg-config 的源码,这里我们需要最新的 0.29.2 版本(之前找到过一个 0.23 的编译版本但是不兼容),解压缩之后,用 Git Bash Here 打开目录,运行 ./configure --prefix=/e/MinGW/mingw64 --with-internal-glib 命令,无误之后运行 make & make install ,这样子 pkg-config.exe 就会安装到 MinGW 的 bin 目录下。

  1. 如果提示找不到 make 命令,将 MinGW 的 bin 录下的 mingw32-make.exe 复制一份重命名为 make.exe 即可。
  2. 其他的 pkg-config 的编译选项可以参考这个网址

配置 oci8.pc

根据 GitHub 库的 README 文件,我们还需要一份 oci8.pc 文件,它需要放置在 {MinGW 目录}\lib\pkg-config 目录下(如果没有则创建),同时要将这个地址配置到一个新的环境变量 PKG_CONFIG_PATH 上。oci8.pc 文件的内容参考网上的可能会有过时(即使我现在的也不例外),最好是参照 GiHub 库的官网的 oci8.pc Examples ,这里我的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
prefix=E:/instantclient_19_3
exec_prefix=E:/instantclient_19_3
libdir=${prefix}/sdk/lib/msvc
includedir=${prefix}/sdk/include/

glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums

Name: oci8
Description: oci8 library
Libs: -L${libdir} -loci
Cflags: -I${includedir}
Version: 11.2

这里一些说明:

  1. prefix 是 instantclient 的地址,根据自己的实际情况而定,我这里是 E:/instantclient_19_3 。
  2. 一般来说 exec_prefix 的值和 prefix 的值一样。
  3. Version 是要链接的 Oracle 的版本,我这里统一是 11.2g,这个根据实际的情况而定。

下载 go-oci8

接下来的事情就简单了,go get 走起(温馨提示:需要 Go 1.9 及以上版本):

1
go get github.com/mattn/go-oci8

没有报错,大功告成。

测试 go-oci8

随便写个程序测试一下,用的 Oracle 自带的 dept 表:

test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"database/sql"
_ "github.com/mattn/go-oci8"
"log"
)

func main() {
db, err := sql.Open("oci8", "scott/tiger@ORCL")
if err != nil {
log.Fatal(err)
}
defer db.Close()

rows, err := db.Query("SELECT DEPTNO, DNAME, LOC FROM DEPT")
if err != nil {
log.Fatal(err)
}

for rows.Next() {
var deptno int64
var dname string
var loc string
rows.Scan(&deptno, &dname, &loc)
log.Printf("DEPTNO = %v, DNAME = %v, LOC = %v \n", deptno, dname, loc)
}
rows.Close()
}

go run test.go 输出结果

1
2
3
4
5
2019/11/04 15:40:23 DEPTNO = 10, DNAME = ACCOUNTING, LOC = NEW YORK
2019/11/04 15:40:23 DEPTNO = 20, DNAME = RESEARCH, LOC = DALLAS
2019/11/04 15:40:23 DEPTNO = 30, DNAME = SALES, LOC = CHICAGO
2019/11/04 15:40:23 DEPTNO = 40, DNAME = OPERATIONS, LOC = BOSTON

到此,告一段落。

参考资料