golang ODBC 访问access数据库(问题解决之心理路程)
最近项目需要,需要操作access,以前是用VC++ OLE访问,网络用ACE库,感觉很庞大。。。决定用go试试
网上用的最多的就是这个https://github.com/weigj/go-odbc
安装方式如下:
ODBC database driver for Go Install:
cd $GOPATH/src
git clone git://github.com/weigj/go-odbc.git odbc
cd odbc
go install
测试时碰到好多坑。。。。。
第1次当运行go install时,
坑爹1:发现找不到gcc,哦, 推测cgo去链接odbc32的dll,需要gcc编译环境,幸亏哥搞cocos2d-x时电脑上已经装了庞大的cygwin,于是启动Cygwin Terminal,跳转到odbc目录,
第2次当运行go install时,
坑爹2:提示access limit。。可是在console里直接运行gcc -v是存在的,感觉是gcc这个是linux的符号链接,推测go install时可能没用利用cygwin的环境设置,有点冲突,于是删掉gcc这个符号link,把真正的gcc-4.exe改名为gcc.exe,
第3次当运行go install时,
坑爹3:提示找不到ODBC的函数符号,你妹,不得不fuck source code了,读源码odbc.go,发现导入有个macro定义,
#ifdef __MINGW32__
#include <windef.h>
#else
typedef void* HANDLE;
#endif
原来odbc.go编译依赖MINGW环境,于是下载mingw,安装完后,把mingw的bin目录加到系统path里,编译成功。
go run 下面的例子代码,
package main import (
"database/sql"
"fmt"
_ "odbc/driver"
) func main() {
conn, err := sql.Open("odbc", "driver={Microsoft Access Driver (*.mdb)};dbq=d:\\test.mdb")
if err != nil {
fmt.Println("Connecting Error")
return
}
defer conn.Close()
stmt, err := conn.Prepare("select * from test") //ALTER TABLE tb ALTER COLUMN aa Long
if err != nil {
fmt.Println("Query Error")
return
}
defer stmt.Close()
row, err := stmt.Query()
if err != nil {
fmt.Print(err)
fmt.Println("Query Error")
return
}
defer row.Close()
for row.Next() {
var ID string
var SequenceNumber int
var ValueCode string
if err := row.Scan(&ID, &SequenceNumber, &ValueCode); err == nil {
fmt.Println(ID, SequenceNumber, ValueCode)
}
}
fmt.Printf("%s\n", "finish")
return
}
坑爹4:居然提示
fatal error: malloc/free - deadlock
[signal 0xc0000005 code=0x1 addr=0x2f0 pc=0x419258] goroutine 1 [syscall]:
[fp=0x10815fc] return()
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/runtime/asm_386.s:472
[fp=0x1081624] runtime.cgocall(0x470a23, 0x1081630)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/runtime/cgocall.c:162 +0x10a
[fp=0x1081630] odbc._Cfunc_SQLFreeHandle(0x400003, 0xb115e8, 0x1081650)
C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/go-build619492171/odbc/_obj/_cgo_defun.c:144 +0x31
[fp=0x1081640] odbc.(*Statement).free(0x2f860140)
odbc.go:745 +0x32
[fp=0x1081648] odbc.(*Statement).Close(0x2f860140)
odbc.go:752 +0x28
[fp=0x1081650] odbc/driver.(*stmt).Close(0x2f860148, 0x2f8601c8, 0x405a2b)
E:/go/src/odbc/driver/sql.go:107 +0x2a
[fp=0x108168c] database/sql.(*DB).noteUnusedDriverStatement(0x2f884300, 0x2f8821e0, 0x2f882240, 0x2f860148)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/database/sql/sql.go:554 +0x17a
[fp=0x10816d0] database/sql.(*Stmt).finalClose(0x2f8862d0, 0x2f8601b8, 0x0)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/database/sql/sql.go:1264 +0x84
[fp=0x10816e0] database/sql.func·002(0x2f884310, 0x2f894720)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/database/sql/sql.go:372 +0x2c
[fp=0x1081700] database/sql.(*DB).removeDep(0x2f884300, 0x2f894720, 0x2f8862d0, 0x49c740, 0x2f8862d0, ...)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/database/sql/sql.go:351 +0x78
[fp=0x1081720] database/sql.(*Stmt).Close(0x2f8862d0, 0x0, 0x0)
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/database/sql/sql.go:1259 +0x117
[fp=0x10817c4] main.main()
E:/go/src/testaccessdb/testdb.go:12 +0xbf
[fp=0x10817dc] runtime.main()
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/runtime/proc.c:182 +0x8e
[fp=0x10817e0] runtime.goexit()
C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist465310315/go/src/pkg/runtime/proc.c:1223 goroutine 2 [syscall]:
exit status 2
这郁闷了,google了半天也没有解决方案,发现golang issue里有这个问题,可是那货说最新的go version已经解决了,可哥就是最新的版本啊,顺手甚至提交这个bug到golang,决定放弃了。。。。。
可是哥的钻研精神此刻闪闪发光,照亮我的前程了,反复N遍,逐渐删除测试代码,最后发现
stmt.Query()
这个函数删掉就pass了!
于是仔细读上面的堆栈垃圾信息发现问题可能是free 句柄odbc._Cfunc_SQLFreeHandle多次导致,怀疑是这个github.com/weigj/go-odbc.git 库自带的bug,不是go的问题,于是使用已经广而知之神器武功套路log大法,在free函数开始和结束处 加log, go run again发现free()函数果然被调用了两次。。。
于是哥修改
func (stmt *Statement) free() {
C.SQLFreeHandle(C.SQL_HANDLE_STMT, stmt.handle)
}
为
func (stmt *Statement) free() {
if stmt.handle != nil {
C.SQLFreeHandle(C.SQL_HANDLE_STMT, stmt.handle)
stmt.handle = nil
}
}
预期中的测试通过。。。错误提示没有了,只有闪闪发光的finish。。。
善后:尼玛,发现这作者两年没更新,而网上的代码片段都指向这个库。。。于是哥提交了一份修复bug的完整代码,请参考https://github.com/philsong/golang_samples
问题解决了,感觉这个库不是很成熟,不过写tool utility可以凑合用。
最后,你若用好,便是晴天。
golang ODBC 访问access数据库(问题解决之心理路程)的更多相关文章
- [转载]Unity3D 访问Access数据库
在开始这个小教程之前呢,其实在网上你已经可以找到相关的资料了,但是我还是要把我自己做练习的一点东西分享出来.写这个教程的主要原因呢,是一个朋友在u3d的官网论坛里,找到了这个demo,但是在他使用的过 ...
- Unity访问Access数据库
首先,准备工作: 创建一个Access 数据库,命名AccessTest.accdb,添加一些数据用于测试 准备System.Data.dll与System.EnterpriseServices.dl ...
- C#.NET ORM 如何访问 Access 数据库 [FreeSql]
最近很多 .net QQ 群无故被封停,特别是 wpf 群几乎全军覆没.依乐祝的 .net6交流群,晓晨的 .net跨平台交流群,导致很多码友流离失所无家可归,借此机会使用一次召唤术,有需要的请加群: ...
- ADO访问Access数据库错误解决心得随笔
最近在用ADO访问Access数据库的时候出现了一个奇怪的错误,觉得有必要记录下来,和大家分享一下. 环境 win7 x86系统: VS2012编译器: Office2010: Access2000~ ...
- 如何使用.net访问Access数据库 (转)
前言:今天整理程序,看到之前写的一个Demo,也不知道是从哪里参考的了,写到这里,留作备用吧. 使用.net访问Access数据库:1.BL层:新增一个DataAccess类. Code].Defau ...
- Excel中使用VBA访问Access数据库
VBA访问Access数据库 1. 通用自动化语言VBA VBA(Visual Basic For Application)是一种通用自动化语言,它可以使Excel中的常用操作自动化,还可以创建自定义 ...
- vc访问ACCESS数据库
在现代软件开发中,数据库技术被越来越广泛应用,很多项目都存在着大量的数据需要存储,通常都会采用数据库来存储这些数据.最初,数据库厂商推出一个新的数据库产品时,相应的,他会为程序员提供一套访问该数据库的 ...
- Jackcess 1.2.13 发布,Java 访问 Access 数据库
Jackcess 1.2.13 包含新的方法用于在数据库和附件内容解码中查找复杂值类型的关系,修复了 CodeHandler 相关的一些小 bug. Jackcess 是一个Java 类库,用来读写微 ...
- 访问Access数据库(有多个数据库时 体现多态)
如果想编写单机版MIS.小型网站等对数据库性能要求不高的系统,又不想安装SQLServer,可以使用Access(MDAC),只要一个mdb文件就可以了.使用Access创建mdb文件,建表.OleD ...
随机推荐
- Server.MapPath(string sFilePath) 报未将对象引用到实例异常
System.Web.HttpContext.Current.Server.MapPath(string sfilePath)将虚拟路径转换成物理路径.这个必须在aspx或者MVC中Action调用才 ...
- java正则表达式,将字符串中\后的第一个字母变成大写
java正则表达式,将字符串中\后的第一个字母变成大写 例子是比较简单,注意的是java中的“\\”意义是:我要插入一个正则表达式的反斜线,所以其后面的字符有特殊有意义.所以普通反斜线应该是" ...
- ToDoList-学习中看到的知识盲点
1. java中的volatile关键字的作用 2. java类加载器 3. Android源码编译 4. MediaPlayer的用法 5. Html5和web app
- HDU 5584 LCM Walk(数学题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5584 题意:(x, y)经过一次操作可以变成(x+z, y)或(x, y+z)现在给你个点(ex, e ...
- leetcode Climbing Stairs python
class Solution(object): def climbStairs(self, n): """ :type n: int :rtype: int " ...
- nodejs安装指定版本
由于express有各种不同的版本,不同的版本开发方式有所不同,如果想安装指定版本可以选择全局安装指定版本: 安装步骤如下: (1) 安装2.5.8版本的express的方法: C:\Users\Li ...
- 从零开始PHP学习 - 第三天
写这个系列文章主要是为了督促自己 每天定时 定量消化一些知识! 同时也为了让需要的人 学到点啥~! 本人技术实在不高!本文中可能会有错误!希望大家发现后能提醒一下我和大家! 偷偷说下 本教程最后的目 ...
- codeforces 589F. Gourmet and Banquet 二分+网络流
题目链接 给你n种菜, 每一种可以开始吃的时间不一样, 结束的时间也不一样. 求每种菜吃的时间都相同的最大的时间.时间的范围是0-10000. 看到这个题明显可以想到网络流, 但是时间的范围明显不允许 ...
- scanf一次给多个变量赋值
本节课程笔记: 一是对多个变量进行赋值,二是对非法输入的值做正确处理(处理方式了解即可,相关函数知识后期讲解),三是美化scanf代码加入输出说明. /* Name:scanf一次给多个变量赋值 Co ...
- 转: mysql create view 创建视图
以下的文章主要是对MySQL视图的描述,其中包括MySQ视图L概述,以及创建MySQL视图-create view与修改MySQL视图--alter view等相关内容的具体描述,以下就是文章的具体内 ...