Go语言中,对Oracle进行操作,比访问其他常见DB可谓是要麻烦一些,显而易见的问题是库的选择,这里我尝试了两种库:

库的选择

go-ora是原生Go实现的,不需要依赖CGo,相对比较方便,也比较易用,但在使用过程中,使用该库连接Oracle一段时间后,其会请求出错,我也对此提了issue,以及解决方法,但由于联系不上maintainer,所以无法确认解决方法是否靠谱了。

https://github.com/sijms/go-ora/issues/240

也有人遇到了与我相似的问题,用我issue上提到的解决方式解决了该问题,但我依然不推荐这么操作。

go-oci8是使用了CGo实现了Oracle的客户端,虽然对环境有所依赖,好在库很稳定,不用担心出幺蛾子,且xorm实验性的支持,对只使用oracle基础功能来说,还是够用的。

推荐使用下面这种。

SQL使用

大小写

在使用oracle Console时,输入表名、字段,不管大小写都可以识别。但其实这里有个误区。

Oracle默认是大写的,也就是说在没有使用双引号"对表名和列名进行限定的时候,表名不过是小写还是大写,最后都默认成了大写。

若是以双引号进行限定后,字段大小写就不再转化为默认的大写了。

1
2
3
CREATE TABLE department (
id NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);

上面字段都会转化为大写,DEPARTMENTIDDESCRIPTION

1
2
3
4
5
SELECT id FROM department;     √

SELECT ID FROM department; √

SELECT "id" FROM department; ×

明白上述所述后,使用xorm时需要注意的是。

在使用xorm自动创建表时,其会根据你的注释的大小写,创建字段。这里就要区分一下了。

1
2
3
4
type Info struct {
Type int8 `json:"type,omitempty" xorm:"number(8) 'type'"`
Sn string `json:"sn,omitempty" xorm:"varchar2(64) 'sn'"`
}

时间

对时区的设置,这里是:

1
2
ALTER DATABASE SET TIME_ZONE='Asia/Shanghai';
ALTER SESSION SET TIME_ZONE ='Asia/Shanghai';

update_timecreated_time常见的两个时间,保存时间戳是没有什么问题(int64)。但要保存time时间格式,估计会发现没法存进去。

update_time可以使用raw sql:

1
2
3
UPDATE xxxx SET "max_id"="max_id" + "step", "update_time" = TO_TIMESTAMP('%s', 'YYYY-MM-DD HH24:MI:SS.FF6') WHERE "biz_tag"='123'

时间传入:time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05.0000")

created_time

1
2
3
4
5
6
7
8
9
10
CREATE TABLE "xxxxxx"(
"id" NUMBER DEFAULT 1,
"created_time" TIMESTAMP WITH LOCAL TIME ZONE DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY("id")
)

type xxxxx struct {
CreatedTime time.Time `json:"created_time,omitempty" xorm:"TIMESTAMP(6) WITH LOCAL TIME ZONE default CURRENT_TIMESTAMP 'created_time'"` // 记录创建时间
}

主键

12版本以前没法像MySQL一样生成自增主键,需要一些曲线救国的方式。

使用SYS_GUID(),系统根据当前时间和机器码,生成全球唯一的一个序列号。

1
2
3
CREATE TABLE department (
ID varchar2(50) default SYS_GUID() not null primary key,
DESCRIPTION VARCHAR2(50) NOT NULL);

自增ID的实现:

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
Oracle 12c之前:
-- 表定义
CREATE TABLE departments (
ID NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);

ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));

CREATE SEQUENCE dept_seq START WITH 1;

-- 触发器定义
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON departments
FOR EACH ROW

BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;

12c:
CREATE TABLE MAPS
(
MAP_ID INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL,
MAP_NAME VARCHAR(24) NOT NULL,
UNIQUE (MAP_ID, MAP_NAME)
);