使用Go语言进行SQLite数据库的读写操作

发表时间: 2020-08-27 00:47

概要:本文学习如何在go软件中读写sqlite3。

为何选择sqlite?

sqlite3 基本语法和mysql相近。更少也意味着更简单的功能。仅支持int,real,text,blob 4个基本类型。模糊查找也仅仅支持like。

因为我准备在记事本这个小工具中使用,故mysql 显得太大。mysql部署不方便,而sqlite却仅仅只有一个文件,小巧方便部署,即使将来把记事本做成手机APP,也不需要更改数据库直接可以扩展。

去哪里找driver?

大家还记得我前面的文章《GO语言中如何操作Excel表格》吧?(如果不记得可以往前翻)里面有一个重要的技巧:Go语言的包在 https://pkg.go.dev/ 打开,搜索,录入关键字 sqlite3 。就能找到了。

选mattn的MIT协议的驱动 “
github.com/mattn/go-sqlite3
"

下面就实例操作一下。

一个简单的例子,读写sqlite

前提:

记事本工具,数据表设计如下:

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 的表


读取本地png图片到buffer

打开图片文件后,byte.Buffer可以通过ReadFrom(file)读取文件指针指向的内容--图片文件二进制数据。注意,buffer.Grow(int)应该是在read过程中自动增长的。故上面代码中Grow一句可以去掉。调试发现,如果通过Grow指定Buffer大小,则后面的ReadFrom(f)刚好够用,不会增两倍需求字节长度。如果去掉Grow这句,则ReadFrom(f)这句会导致Buffer暴增2倍左右字节。

写一条记录到数据库

知识点:所有开关资源,在打开后,立即调用 defer close


sqlie中刚写入的记录

通过Navcat工具查看Sqlite数据库表mainmenu,可以看到刚写入的记录,blob字段可以以图片方式显示。证明写入正常。

查询的写法


sqlite查询

如何模拟一个error?

/// 下面这个函数实现如何从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)