参考连接: http://jmoiron.github.io/sqlx/
sqlx是一个go语言包,在内置database/sql包之上增长了不少扩展,简化数据库操做代码的书写mysql
若是对go语言的sql用法不熟悉,能够到下面网站学习:
http://go-database-sql.org/git
若是对于golang语言不熟悉,能够到下面网站学习:
https://blog.csdn.net/wdy_yx
因为database/sql接口是sqlx的子集,当前文档中全部关于database/sql的用法一样用于sqlxgithub
安装sqlx驱动golang
go get github.com/jmoiron/sqlx
本文访问sqlite数据sql
go get github.com/mattn/go-sqlite3
sqlx设计和database/sql使用方法是同样的。包含有4种主要的handle types:数据库
全部的handler types都提供了对database/sql的兼容,意味着当用调用sqlx.DB.Query时,能够直接替换为sql.DB.Query。这就使得sqlx能够很容易的加入到已有的数据库项目中。缓存
此外,sqlx还有两个cursor类型:并发
一个DB实例并非一个连接,可是抽象表示了一个数据库。这就是为何建立一个DB时并不会返回错误和panic。它内部维护了一个链接池,当须要进行链接的时候尝试链接。你能够经过Open建立一个sqlx.DB或经过NewDb从已存在的sql.DB中建立一个新的sqlx.DBapp
var db *sqlx.DB // exactly the same as the built-in db = sqlx.Open("sqlite3",":memory:") // from a pre-existing sql.DB; note the required driverName db = sqlx.NewDb(sql.Open("sqlite3",":memory:"),"sqlite3") // force a connection and test that it worked err = db.Ping()
在一些环境下,你可能须要同时打开一个DB链接。能够调用connect,这个函数打开一个新的DB并尝试Ping。MustConnect函数在连接出错时会panic。函数
var err error // open and connect at the same time: db, err = sqlx.Connect("sqlite3", ":memory:") // open and connect at the same time, panicing on error db = sqlx.MustConnect("sqlite3",":memory:")
sqlx中的handle types实现了数据库查询相同的基本的操做语法。
对内置语法的扩展
还有下面新的语法
Exec和MustExec从链接池中获取一个链接而后只想对应的query操做。对于不支持ad-hoc query execution驱动,在操做执行的背后会建立一个prepared statement。
在结果返回前这个connection会返回到链接池中。
schema := `CREATE TABLE place ( country text, city text NuLL, telcode integer);` // execte a query on the server result, err := db.Exec(schema) // or, you can use MustExec, which panics on error cityState := `INSERT INTO place (country, city, telcode) VALUES (?,?)` countryCity := `INSERT INTO place (country, city, telcode) VALUES (?,?,?)` db.MustExec(cityState,"Hong Kong", 852) db.MustExec(cityState, "Singapore", 65) db.MustExec(countrycity, "South Africa", "Johannesbury", 27)
上面代码中result有两个可能的数据LastInsertd() or RowsAffected(),依赖不一样的驱动
mysql代码中,在含有auth-increment key的表中执行插入操做会获得LatInsertId(),在PostgreSQL中这个信息只有在使用RETURNING语句的row cursor中才会返回
代码中? 占位符,称为bindvars,很是重要,你能够老是使用它们来向数据库发送数据,能够用来组织SQL injection攻击。
database/sql并不会对查询语句进行任何的校验,传入什么就发送到server是什么。
除非driver实现特定的接口,query在数据库执行以前会准备好。不一样的数据库的bindvars不同。
其余数据库可能还不同。你可使用sqlx.DB.Rebind(string) string函数利用? 语法来获得一个合适在当前数据库上执行的query语句
关于binddvars常见的误解是他们用于插值。他们只用于参数化,不容许改变sql语句的合法接口。例如,下面的用法是会报错的。
// doesn't work db.Query("SELECT * FROM ?","mytable") // also doesn't work db.Query("SELECT ?,? FROM people","name","location")
Query是database/sql中执行查询主要使用的方法,该方法返回row结果。Query返回一个sql.Rows对象和一个error对象
// fetch all places from the db rows, err := db.Query("SELECT country,city, telcode FROM place") // iterate over each row for rows.Next() { var country string // note that city can be NULL, so we use the NullString type var telcode int err = rows.Scan(&country,&city,&telcode) }
在使用的时候应该把Rows当成一个游标而不是一系列的结果。尽管数据库驱动缓存的方法不同,
通赤Next()迭代每次获取一列结果,对于查询结果很是巨大的状况下,能够有效的限制内存的使用,
Scan()利用reflect把sql每一列结果映射到go语言的数据类型如string, []byte等。若是你没有遍历彻底部的rows结果,
必定要记得在把connection返回到链接池以前调用rows.Close()。
Query返回的error有多是在server准备查询的时候发生的,也有多是在执行查询语句的时候发的。例如可能从链接池中获取一个坏的连级(尽管数据库会尝试10次去发现或建立一个工做链接).
通常来讲,错误主要由错误的sql语句,错误的相似匹配,错误的域名或表名等。
在大部分状况下,Rows.Scan()会把从驱动获取的数据进行拷贝,不管驱动如何使用缓存。特殊类型sql.RawBytes能够用来从驱动返回的数据中获取一个zero-copy的slice byte。当下次调用Next的时候,这个值就不在有效了,由于它指向的内存已经被驱动重写了别的数据。
Query使用的connection在全部的rows经过Next()遍历完后或者调用rows.Close()后释放。
Queryx和Query行为很类似,不过返回一个sqlx.Rows对象,支持扩展的scan行为。
type Place struct { Country string City sql.NullString TelephoneCode int `db:"telcode` } rows, err := db.Queryx("SELECT * FROM place") for rows.Next() { var p Place err = rows.StructScan(&p) }
sqlx.Rowx的主要扩展就是StructScan,能够自动把查下结果扫描到对应结构体中的域(fileld)中。
注意结构体中域(field)必须是可导出(exported)的,这样sqlx才可以写入值到结构体中。
正如在上面代码中所示,能够利用db结构体标签来指定结构体field映射到数据库中特定的列名,或者用db.MapperFunc()来指定默认的映射。
db默认对结构体的filed名执行strings.Lower后,和数据库的列名进行匹配。关于StructScan,SliceScan,MapScan更详细的内容请参见后面章节advanced scanning。
QueryRow从数据库server中获取一列数据。它从链接池中获取一个链接。而后执行Query,返回一个Row对象,这个对象有一个自已内部的Rows对象。
row := db.QueryRow("SELECT * FROM place WHERE telcode=?",852) var telcode int err = row.Scan(&telcode)
不像Query, QueryRow只返回一个Row类型,并不返回error,若是在执行查询过程当中出错,则错误经过Scan返回,若是查询结果为空,则返回sql.ErrNoRows。
若是Scan自己出错,error一样由scan返回。
QueryRow使用的connection当result返回的时候就关闭了,也就意味着使用QueryRow的时候不可以使用sql.RawByes,由于driver使用sql.RawBytes引用内存,在connection回收后可能也会无效。
QueryRowx返回一个sqlx.Row而不是sql.Row,它实现了跟Rows相同的scan方法如上,同时还有高级的scan方法以下: (更高级的scan方法advanced scanning section)
var p Place err := db.QueryRows("SELECT city, telcode FROM place LIMIT 1").StructScan(&p)
Get和Select是一个很是省时的扩展。它们把query和很是灵活的scan语法结合起来。为了更加清晰的介绍它们,咱们先讨论下什么是scannalbe:
a value is scannable if it is not a struct, eg string,int a value is scannable if it implements sql.Scanner a value is scannable if it is a struct with no exported fields (eg time.Time)
Get和Select对scannable的类型使用rows.scan,对non-scannable的类型使用rows.StructScan。Get用来获取单个结果真后Scan,Select用来获取结果切片。
p := Place{} pp := []Place{} // this will pull the first place directly into p err = db.Get(&p,"SELECT * FROM place WHERE telcode > ?", 50) // they work with regular types as well var id int err = db.Get(&id,"SELECT count(*) FROM place") // fetch at most 10 place names var names []string err = db.Select(&names,"SELECT name FROM place LIMIT 10")
Get和Select在执行查询后就会关闭Rows,而且在执行阶段遇到任何问题都会返回错误。因为它们内部使用的StructScan,因此下文中
advanced scanning section讲的特征也适用于Get和Select.
Select能够提升编码小路,可是要注意Select和Queryx是有很大不一样的,由于Select会把整个结果一次放入内存。若是查询结果没有限制特定的大小,那么最好使用Query/StructScan迭代方法。
为了使用transactions,必须使用DB.Begin()来建立,下面的代码是错误的:
db.MustExec("BEGIN;") db.MustExec(...) db.MustExec("COMMIT;")
Exec和其余查询语句会向DB请求一个connection,执行完后就返回到链接池中,并不能保证每次获取的connection就是BEGIN执行时使用的那个,因此正确的作法要使用DB.Begin:
tx, err := db.BEGIN err = tx.Exec(...) err = tx.Commit()
DB除了Begin以外,还可使用扩展Beginx()和MustBegin(),返回sqlx.Tx:
tx := db.MustBegin() tx.MustExec(...) err = tx.Commit()
sqlx.Tx拥有sqlx.DB拥有的全部的haandle extensions.
因为transaction是一个connection状态,因此Tx对象必须绑定和控制单个connection。一个Tx会在整个生命周期中保存一个connection,而后在调用commit或Rollback()的时候释放掉。你在调用这几个函数的时候必须十分当心,不然connections会一直被占用直到被垃圾回收。
因为在一个transaction中只能有一个connection,因此每次只能执行一条语句。在执行另外的query操做以前,cursor对象Row*和Rows必须被Scanned或Closed。若是在数据库给你返回数据的时候你尝试向数据库发送数据,这个操做可能会中断connection。
最后,Tx对象仅仅执行了一个BEGIN语句和绑定一个connection,它其实并无在server上执行任何操做。而transaction真实的行为包含locking和isolation,在不一样数据库上实现是不一样的。
对于大部分的数据库来讲,当一个query执行的时候,在数据库内部statement其实已经准备好了。而后你能够经过sqlx.DB.Prepare()准备statements,便于后面在别的地方使用。
stmt, err := db.Prepare(`SELECT * FROM place WHERE telcode = ?`) row = stmt.QueryRow(65) tx, err := db.Gegin() txStmt, err := tx.Prepare(`SELECT * FROM place WHERE telcode = ?`) row = txStmt.QueryRow(852)
Prepare实际上在数据库上执行preparation操做,因此它须要一个connection和它的connection state。
database/sql把这部分进行了抽象,自动在新的connection上建立statement,这样开发者就能经过stmt对象在多个connection上并发执行操做。
Preparex()返回一个sqlx.Stmt对象,包含sqlx.DB和sqlx.Tx全部的handle扩展(方法).
sql.Tx对象含有一个Stmt()方法,从已存在的statement中返回一个特定于改transaction的statement。
sqlx.Tx一样含有一个Stmtx()方法,从已有的sql.Stmt或sqlx.Stmt中建立一个特定于transaction的sqlx.Stmt.
"In" Queries 因为database/sql并不会分析你的查询语句而后直接把参数传递给driver,这样对于IN