概要:本文学习如何在go软件中读写sqlite3。
sqlite3 基本语法和mysql相近。更少也意味着更简单的功能。仅支持int,real,text,blob 4个基本类型。模糊查找也仅仅支持like。
因为我准备在记事本这个小工具中使用,故mysql 显得太大。mysql部署不方便,而sqlite却仅仅只有一个文件,小巧方便部署,即使将来把记事本做成手机APP,也不需要更改数据库直接可以扩展。
大家还记得我前面的文章《GO语言中如何操作Excel表格》吧?(如果不记得可以往前翻)里面有一个重要的技巧:Go语言的包在 https://pkg.go.dev/ 打开,搜索,录入关键字 sqlite3 。就能找到了。
选mattn的MIT协议的驱动 “
github.com/mattn/go-sqlite3"
下面就实例操作一下。
前提:
记事本工具,数据表设计如下:
CREATE TABLE if not exists "mainmenu" ( "id" INTEGER NOT NULL, //自增长id ,即节点id "parentid" INTEGER, //节点的父节点 "title" TEXT, //节点标题 "picicon" blob, //节点图标 "is_delete" integer, //是否删除节点 "showorder" integer, //节点显示序号 PRIMARY KEY ("id"));
下面看下代码:
第一个要点,导入匿名驱动
import ("database/sql"//_ "github.com/lib/pq" // enable support for Postgres//_ "github.com/go-sql-driver/mysql" // enable support for MySQL_ "github.com/mattn/go-sqlite3" //这个就是驱动)
驱动导入按匿名方式导入,这样编译时就能找到相应的依赖。
第二点,为了简洁,把一条记录需要的数据放到一起
type ANODE struct{ Parentid int Title string b bytes.Buffer // 对应字段 Picicon blob Showorder int}
第三点,声明一个全局变量记录连接
var gdb *sql.DB
然后,在main()中就可以这样使用了:
//dbgdb = opendb("./ctb.sqlite3")defer gdb.Close()createtable(gdb)
//如果有就打开,如果没有则新建func opendb(dbfilepathname string) *sql.DB { db, err := sql.Open("sqlite3", dbfilepathname) //"./ctb.db" errlog(err) db.SetMaxOpenConns(1) return db //defer db.Close() //When you get a database is locked. Please use the following options. //Add to DSN: cache=shared //db, err := sql.Open("sqlite3", "file:locked.sqlite?cache=shared")}
//mkcontent #记事内容,非文本部分以key引用blobjson中的数据//picjson #记录文本中插入的非文本数据func createtable(db *sql.DB) { sqlStmt := ` create table if not exists notes (id integer not null primary key AUTOINCREMENT, title text , subtitle text, keys text, mkcontent text, picjson blob ); delete from notes; ` _, err := db.Exec(sqlStmt) if err != nil { log.Printf("%q: %s\n", err, sqlStmt) } // 主菜单,即左导航栏tree sqlStmt = `CREATE TABLE if not exists "mainmenu" ( "id" INTEGER NOT NULL, "parentid" INTEGER, "title" TEXT, "picicon" blob, "is_delete" integer, "showorder" integer, PRIMARY KEY ("id") );` _, err = db.Exec(sqlStmt) if err != nil { log.Printf("%q: %s\n", err, sqlStmt) }}
下面代码是从文件图图片,然后写一条记录到sqlite,其中图片数据直接按字节存到blob字段。
var anode ANODEreadimgfrombuf(nil,"./8.png",&anode.b) //读取一个图片文件到bufferanode.Title="测试title"insert2mu(gdb,anode) // insert 一条记录到sqlite 的表
打开图片文件后,byte.Buffer可以通过ReadFrom(file)读取文件指针指向的内容--图片文件二进制数据。注意,buffer.Grow(int)应该是在read过程中自动增长的。故上面代码中Grow一句可以去掉。调试发现,如果通过Grow指定Buffer大小,则后面的ReadFrom(f)刚好够用,不会增两倍需求字节长度。如果去掉Grow这句,则ReadFrom(f)这句会导致Buffer暴增2倍左右字节。
知识点:所有开关资源,在打开后,立即调用 defer close。
通过Navcat工具查看Sqlite数据库表mainmenu,可以看到刚写入的记录,blob字段可以以图片方式显示。证明写入正常。
/// 下面这个函数实现如何从error中恢复func simulate_err() { defer func() { if p := recover(); p != nil { err := fmt.Errorf("internal error: %v", p) errprint(err) } }() // your code ...... // 模拟一个错误,触发之 。被匿名函数捕获:从error 中恢复,并打印 var EOF = errors.New("EOF") panic(EOF )}func errlog(e error,v ...interface{}) { if e != nil{ log.Fatal(e,">>",v) }}func errprint(e error,v ...interface{}) { if e != nil{ fmt.Println(e,">>",v) }}
1、sqlite驱动的导入
2、open ,创建,增删改查。代码中没有提到update,但看了代码后想必你已经会写了。
3、defer close()的用法
4、bytes.Buffer 的用法
5、模拟一个error,并恢复的方法
我是程序员黑洞,正学Gotk3 GUI编程,欢迎关注,留言,欢迎参与我的gitee mynote项目(https://gitee.com/laogg)