sqlx使用说明

sqlx使用指南

参考链接: http://jmoiron.github.io/sqlx/
sqlx是一个go语言包,在内置database/sql包之上增加了很多扩展,简化数据库操作代码的书写

资源

如果对go语言的sql用法不熟悉,可以到下面网站学习:
http://go-database-sql.org/

如果对于golang语言不熟悉,可以到下面网站学习:
https://blog.csdn.net/wdy_yx
由于database/sql接口是sqlx的子集,当前文档中所有关于database/sql的用法同样用于sqlx

开始

安装sqlx驱动

go get github.com/jmoiron/sqlx

本文访问sqlite数据

go get github.com/mattn/go-sqlite3

Handle Types

sqlx设计和database/sql使用方法是一样的。包含有4种主要的handle types:

  • sqlx.DB: 和sql.DB相似,表示数据库
  • sqlx.Tx: 和sql.Tx相似,表示transacion
  • sqlx.Stmt: 和sql.Stmt相似,表示prepared statement.
  • sqlx.NamedStmt: 表示prepared statement(支持named parameters)

所有的handler types都提供了对database/sql的兼容,意味着当用调用sqlx.DB.Query时,可以直接替换为sql.DB.Query。这就使得sqlx可以很容易的加入到已有的数据库项目中。

此外,sqlx还有两个cursor类型:

  • sqlx.Rows 和sql.Rows类似,Queryx返回。
  • sqlx.Row 和 sql.Row类似,QueryRowx返回。

连接到数据库

一个DB实例并不是一个链接,但是抽象表示了一个数据库。这就是为什么创建一个DB时并不会返回错误和panic。它内部维护了一个连接池,当需要进行连接的时候尝试连接。你可以通过Open创建一个sqlx.DB或通过NewDb从已存在的sql.DB中创建一个新的sqlx.DB

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:")

Querying 101

sqlx中的handle types实现了数据库查询相同的基本的操作语法。

  • Exec(...) (sql.Result,error) 和database/sql相比没有改变
  • Query(...) (*sql.Rows, error) 和database/sql相比没有改变
  • QueryRow(...) *sql.Row 和database/sql相比没有改变

对内置语法的扩展

  • MustExec()sql.Result - Exec, but panic or error
  • Queryx(...) (*sqlx.Rows, error) - Query, but return an sqlx.Rows
  • QueryRows(...) *sqlx.Row - QueryRow, but return an sqlx.Row

还有下面新的语法

  • Get(dest interface{},...) error
  • Select(dest interface{},...) error
    下面会详细介绍这些方法的使用

Exec

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

代码中? 占位符,称为bindvars,非常重要,你可以总是使用它们来向数据库发送数据,可以用来组织SQL injection攻击。

database/sql并不会对查询语句进行任何的校验,传入什么就发送到server是什么。
除非driver实现特定的接口,query在数据库执行之前会准备好。不同的数据库的bindvars不一样。

  • MySQL使用?
  • PostgreSQL使用1,2等等
  • SQLite使用? 或$1
  • Oracle 使用: name

其他数据库可能还不一样。你可以使用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

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 typevar telcode interr = 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 stringCity sql.NullStringTelephoneCode int `db:"telcode`
}rows, err := db.Queryx("SELECT * FROM place")
for rows.Next() {var p Placeerr = rows.StructScan(&p)
}

sqlx.Rowx的主要扩展就是StructScan,可以自动把查下结果扫描到对应结构体中的域(fileld)中。
注意结构体中域(field)必须是可导出(exported)的,这样sqlx才能够写入值到结构体中。
正如在上面代码中所示,可以利用db结构体标签来指定结构体field映射到数据库中特定的列名,或者用db.MapperFunc()来指定默认的映射。
db默认对结构体的filed名执行strings.Lower后,和数据库的列名进行匹配。关于StructScan,SliceScan,MapScan更详细的内容请参见后面章节advanced scanning。

QueryRow

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 and Select

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

为了使用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,在不同数据库上实现是不同的。

Prepared Statements

对于大部分的数据库来说,当一个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.

Query Helpers

"In" Queries
由于database/sql并不会分析你的查询语句然后直接把参数传递给driver,这样对于IN

转载于:https://www.cnblogs.com/Csir/p/9506972.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

填充一个池需要多少个线程?

近几个月来,我们一直看到一小部分但持续的操作失败,并带有一个奇怪的异常– org.springframework.jdbc.CannotGetJdbcConnectionException –“无法获得JDBC连接; 嵌套异常是java.sql.SQLException:客户端尝试检出Connection的尝试…

@font-face 用字体画图标

HTML 1 <body>2 <!-- ul.layout>li*5>a[href#]>i.icon -->3 <!-- Sublime Text 快捷拼写 -->4 <ul class"layout">5 <li><a href"#"><i class"icon">&#xe601;</…

java mapfile_基于文件的数据结构:关于MapFile

MapFile是已经排过序的SequenceFile&#xff0c;它有索引&#xff0c;所以可以按键查找1.MapFile的写操作MapFile的写操作类似于SequenceFile的写操作。新建一个MapFile.Writer实例&#xff0c;然后调用append()方法顺序写入文件内容。如果不按顺序写入&#xff0c;就抛出一个I…

linux scp 命令

scp 命令 scp 命令 意思是 secure copy 即安全拷贝&#xff0c;可以把它看做是 cp 命令的高级版&#xff0c;可以跨主机拷贝。 经常用来在局域网内不同主机之间分享文件&#xff0c;或者在本机与远程主机中分享文件。 在使用的时候就像使用cp 命令一样&#xff0c;第一个参数是…

工厂设计模式–一种有效的方法

如您所知&#xff0c;工厂方法模式或俗称工厂设计模式是“创意设计模式”类别下的一种设计模式。 模式背后的基本原理是&#xff0c;在运行时&#xff0c;我们根据传递的参数获得类似类型的对象。 关于这种模式有很多文章&#xff0c;开发人员可以通过各种方式来实现它。 在本文…

java 循环依赖_解决Java循环依赖的问题

最近看到一个问题&#xff1a;如果有两个类A和B&#xff0c;A类中有一个B的对象b&#xff0c;B类中有一个A的对象a&#xff0c;那么如何解决这两个类的相互依赖关系呢&#xff0c;几天就给大家说一下Java的循环依赖&#xff0c;raksmart服务器。举个栗子1&#xff1a;可以看到A…

CSS块元素水平垂直居中的实现技巧

针对之前遇到过的一些特殊样式的实现&#xff0c;我今天做个总结&#xff0c;目的有二&#xff1a;一是将这些方法记录下来&#xff0c;以便将来需要用到时查找使用。二为将这些大神们智慧的结晶发扬光大&#xff0c;让广大前端程序猿们能够少走弯路。此贴为更新帖&#xff0c;…

Intellij IDEA 将工程转换成maven工程 详解

1> 右键工程&#xff0c;点击 Add Framework Support2> 选中 Maven&#xff0c;再点击 OK3> 工程根目录自动生成 pom.xml 文件&#xff0c;这样 工程就支持 Maven版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 http://blog.csdn.net/che…

设置Apache Hadoop多节点集群

我们正在分享有关在基于Linux的机器&#xff08;多节点&#xff09;上安装Apache Hadoop的经验。 在这里&#xff0c;我们还将分享我们在各种故障排除方面的经验&#xff0c;并在将来进行更新。 用户创建和其他配置步骤– 我们首先在每个集群中添加一个专用的Hadoop系统用户。…

数据结构(七)排序---直接插入排序(稳定)

经典排序算法----直接插入排序算法及其改进&#xff08;稳定&#xff09; 定义&#xff1a; 直接插入排序的基本操作是将一个记录插入到已经排好序的有序表中&#xff0c;从而得到一个新的&#xff0c;记录数加一的有序表。 实现思想 我们预留了一个哨兵&#xff0c;这里我们将…

CSS3中的透明属性opacity的用法实例

实例设置 div 元素的不透明级别&#xff1a;div{opacity:0.5;}完整例子&#xff1a;<!DOCTYPE html><html><head><style> div{background-color:red;opacity:0.5;filter:Alpha(opacity50); /* IE8 以及更早的浏览器 */}</style></head><…

java嵌套类型 无法隐藏外层类型_java内部类深入详解 内部类的分类 特点 定义方式 使用...

java内部类 内部类的分类 特点 定义方式 使用 外部类调用内部类 多层嵌套内部类 内部类访问外部类属性 接口中的内部类 内部类的继承 内部类的覆盖 局部内部类 成员内部类 静态内部类 匿名内部类内部类定义将一个类定义放到另一个类的内部,这就是内部类内部类与组合是完…

java.io.FileNotFoundException: generatorConfig.xml (系统找不到指定的文件。)

在使用MyBatis的逆向工程生成代码时&#xff0c;一直报错java.io.FileNotFoundException: generatorConfig.xml (系统找不到指定的文件。)&#xff0c;如图 文件结构如下&#xff1a; 代码如下&#xff1a; import java.io.File; import java.util.ArrayList; import java.util…

单例设计模式–鸟瞰

几天前&#xff0c;当我回到家乡时&#xff0c;我的一位来自同事的大三学生参加了一家跨国公司的采访&#xff0c;在采访过程中受了重伤。 我的意思是&#xff0c;由于面试小组提出的难题&#xff0c;他无法使面试合格。 当我回到班加罗尔时&#xff0c;他分享了他在技术面试中…

软件实践第一步——自我介绍

031602631&#xff1b;我是超爱美食的苏韫月&#xff1b;我的爱好是品尝所能接触到的所有甜点&#xff08;迟早&#xff01;&#xff09;&#xff1b;我最近新宠&#xff1a;拌面加扁肉&#xff08;京园淳百味&#xff09;&#xff1b;时隔一年我又回归心惊胆颤写博客文的日子。…

CSS3中使用translate() 方法实现元素位置的移动

translate() 方法通过 translate() 方法&#xff0c;元素从其当前位置移动&#xff0c;根据给定的 left&#xff08;x 坐标&#xff09; 和 top&#xff08;y 坐标&#xff09; 位置参数&#xff1a;实例div{transform: translate(50px,100px);-ms-transform: translate(50px,1…

java机器学习库_Amazon Deep Java Library——Java 机器学习工具箱

近年来&#xff0c;人们对机器学习的兴趣稳步增长。具体来说&#xff0c;现在&#xff0c;企业在各种各样的场景中使用机器学习进行图像识别。它在汽车工业、医疗保健、安全、零售、仓库、农场和农业的自动化产品跟踪、食品识别&#xff0c;甚至通过手机摄像头进行实时翻译等方…

阻抗计算

si9000也可以算 一般有点差异&#xff0c;板厂可以微调 加上滤油&#xff0c;实际阻抗会降低2-3欧 影响最大的是层厚 先选择最薄的芯板&#xff0c;注意差分线的阻抗匹配&#xff0c;间距越小&#xff0c;阻抗小&#xff0c; 转载于:https://www.cnblogs.com/IotI/p/8587277.h…

Spring Data Solr教程:动态查询

Solr通常被称为搜索服务器&#xff0c;我们可以在实现全文搜索功能时使用它。 但是&#xff0c;当我们实现从搜索表单获取其输入的搜索功能时&#xff0c;利用Solr的性能通常是明智的。 在这种情况下&#xff0c;执行的搜索查询取决于收到的输入。 这意味着查询参数的数量取决…

[cdq分治][树状数组] Jzoj P4419 hole

Description GFS打算去郊外建所别墅&#xff0c;享受生活&#xff0c;于是他耗费巨资买下了一块风水宝地&#xff0c;但令他震惊的是&#xff0c;一群DSJ对GFS的富贵生活深恶痛绝&#xff0c;决定打洞以搞破坏。现在我们简化一下这个问题&#xff0c;在这片土地上会按顺序发生一…