Gox语言操作数据库也非常方便,语言中已经内置了SQLite、MySQL、Oracle、MS SQL Server等数据库的支持。

以Oracle数据库为例来说,当然系统先要安装Oracle驱动,直接去Oracle官方下载对应的驱动安装即可。Windows下建议安装64位Basic Light版就可以,安装过程也很简单,直接解压到某个目录下,然后将该目录(名为类似“D:\tools\instantclient_19_6”的目录)加入到Windows的PATH中,重启命令提示符窗口或者计算机后就可以使用了。

访问Oracle数据库进行SQL查询的例子如下:

// sqltk库提供访问数据库的一些简单方法
// 连接数据库,Oralce数据库要使用godror驱动
// 用户名、密码、数据库服务器地址和端口、数据库名等均需要替换成自己的
dbT, errT = sqltk.ConnectDB("godror", `username/password@db.example.com:1521/dbname`)
if errT != nil {
printfln("数据库连接错误: %v", errT)
exit()
}
// 注意一定要关闭数据库连接,释放资源,即使是异常退出
defer dbT.Close()
// 拼装SQL语句,建议一般都用拼装的方式,避免传参数的SQL调用方式
// 注意将数据库名、表名和字段名换成自己的
sqlT = `select * from dbname.MY_TABLE_NAME where RECIPE_NO='0200006619210053289'`
// QueryDBNSS函数将查询结果返回为一个二维数组,第一行为列名,第二行开始是数据,所有数据都被转换为字符串表示形式
sqlResultT, errT = sqltk.QueryDBNSS(dbT, sqlT)
if errT != nil {
printfln("获取数据记录失败:%v", errT)
exit()
}
// 查看结果
plv(sqlResultT)
例子中使用到了sqltk库,该库的参考文档可以参考这里.
如果一定需要传参数的方式,需要这样做:
...
sqlT = `select * from dbname.MY_TABLE_NAME where RECIE_NO=:v1 and USER_NO=:v2`
sqlResultT, errT = sqltk.QueryDBNSS(dbT, sqlT, '123456', '789065')
...
即QueryDBNSS函数支持后面跟接任意多个参数,而对Oracle来说,可以用“:v1”这样的方式在SQL语句中表示传入参数的占位。注意,参数占位的方法在不同数据库系统中不尽相同,例如MySQL中是直接用问号“?”表示的。
至于SELECT COUNT(*)这样的操作,可以照下面的方法进行:
...
sqlStrT := `SELECT COUNT(*) FROM ANLA_SEND_REG WHERE ERID='` + emplListT[1] + `' AND (NOTE='' OR NOTE IS NULL)`
countT, errT := sqltk.QueryDBCount(dbT, sqlStrT)
...
sqltk.QueryDBCount函数用于进行只返回一个整数的SQL查询语句。
如果要执行UPDATE、DELETE等操作,则要使用sqltk.ExecV函数,
...
sqlStrT := tk.Spr("UPDATE ANLA_SEND_REG SET NOTE='%v', UPDATE_TIME=sysdate WHERE PICI='%v' AND ERID='%v' AND ID='%v'", "YES", batchNoT, emplListT[1], deviceListT[0])
_, affectedCountT, errT := sqltk.ExecV(dbT, sqlStrT)
if errT != nil || affectedCountT != 1 {
return tk.Spr("更新资产信息失败:%v, %v", errT, sqlStrT)
}
...
这样,基本的数据库操作就都可以实现了。
另外,由于sqltk.ConnectDB函数返回的是Go语言标准库中database/sql中的DB对象,因此可以据此进行符合Go语言标准方式的SQL操作,可以更加细致,实现更加复杂的功能。database/sql的文档可以参看这里。
例如,下面的代码在获得了DB对象后进行了一个数据库事务的处理。
...
txT, errT = dbA.Begin()
if errT != nil {
pl("新建事务时发生错误(%v):%v", tk.Spr("argA: %v", argA), errT)
exit()
}
stmtT, errT = txT.Prepare("insert into MY_TABLE (AccNo, Drcrf, Remark, TradeTime) values(:AccNo, :Drcrf, :Remark, :TradeTime)")
if errT != nil {
pl("准备SQL语句更新记录时发生错误(%v):%v", tk.Spr("argA: %v", argA), errT)
exit()
}
_, errT = stmtT.Exec(AccNoG, argA.Drcrf, "remark here", argA.TradeTime)
if errT != nil {
stmtT.Close()
pl("执行SQL插入记录语句时发生错误(%v):%v", tk.Spr("argA: %v", argA), errT)
exit()
}
txT.Commit()
stmtT.Close()
...

可见Gox语言对于数据库编程的支持还是不错的,注重的是简捷方便。

对于SQLite数据库,数据库驱动名字要把上例中的godror改成sqlite3;MySQL则换成mysql,MS SQL Server则换成sqlserver。

下面再看一个使用SQLite3数据库的例子,SQLite数据库基于文件,无需安装驱动,使用上非常方便,下面这个例子演示了创建一个新的SQLite3的数据库文件,并在其中创建新的表,然后随机插入一些记录,最后进行查询。其中除了数据库创建使用了sqltk库,后续的操作都是使用Go语言标准库的操作,可以借鉴一下。

// 如果存在该库(SQLite库是放在单一的文件中的)则删除该文件
if tk.IfFileExists(`e:\tmpx\test.db`) {
os.Remove(`e:\tmpx\test.db`)
}
// 创建新库
dbT, errT = sqltk.ConnectDB("sqlite3", `e:\tmpx\test.db`)
if errT != nil {
printfln("创建数据库时发生错误:%v", errT)
return
}
// 确保关闭数据库
defer dbT.Close()
//创建表
sqlStmtT = `
create table TEST (ID integer not null primary key, CODE text);
`
_, errT = dbT.Exec(sqlStmtT)
if errT != nil {
printfln("创建表时发生错误:%v", errT.Error())
return
}
// 开始一个数据库事务
txT, errT = dbT.Begin()
if errT != nil {
printfln("新建事务时发生错误:%v", errT.Error())
return
}
// 准备一个SQL语句,用于向表中插入记录
stmtT, errT = txT.Prepare("insert into TEST(ID, CODE) values(?, ?)")
if errT != nil {
printfln("准备SQL语句插入记录时发生错误:%v", errT.Error())
return
}
// 确保关闭SQL语句对象
defer stmtT.Close()
// 向表中插入10条记录
// 每条记录的ID字段用循环变量的值赋值
// CODE字段用随机产生的字符串
for i = 0; i < 10; i++ {
_, errT = stmtT.Exec(i, tk.GenerateRandomString(5, 8, true, true, true, false, false, false))
if errT != nil {
printfln("执行SQL插入记录语句时发生错误:%v", errT.Error())
return
}
}
// 执行事务,此时新纪录才会被真正插入到表中
txT.Commit()
// 进行SQL查询
rowsT, errT = dbT.Query("select ID, CODE from TEST")
if errT != nil {
printfln("执行SQL查询语句时发生错误:%v", errT.Error())
return
}
// 确保关闭数据库查询结果集对象
defer rowsT.Close()
// 遍历查询结果
for {
if rowsT.Next() == false {
break
}
idT = ""
codeT = ""
// 注意Gox语言中取指针要用符号^
errT = rowsT.Scan(^idT, ^codeT)
if errT != nil {
printfln("遍历查询结果时发生错误:%v", errT.Error())
return
}
printfln("ID: %v, CODE: %v", idT, codeT)
}
// 检查查询结果的错误
errT = rowsT.Err()
if errT != nil {
printfln("查询结果有错误:%v", errT.Error())
}
代码中已经有详尽的解释,这段代码执行后,将在E盘的tmpx目录下新增test.db文件,这就是代码创建的新SQLite3的数据库。代码执行的输出如下:
E:\scripts>gox sqlite.gox
ID: 0, CODE: MvDo4GMR
ID: 1, CODE: IGMJi
ID: 2, CODE: 7QJe5eY
ID: 3, CODE: Ot13Fq
ID: 4, CODE: LSntYqa
ID: 5, CODE: ZXvb67Lt
ID: 6, CODE: QMueBp5
ID: 7, CODE: OFDcmo1
ID: 8, CODE: fpMTy5
ID: 9, CODE: ZKvlEF

可以看出,数据库记录成功地添加进去了,并且查询也成功了。