在golang中使用数据库主要依赖database/sql
库以及pg的驱动库。而目前我们常用的pg的驱动库是 github.com/lib/pq
。这里我想说的不是如何去使用它们,毕竟人家文档已经很详细了,这里主要总结了一下自己日常使用中学到的一些技巧。
相同标记重复使用
database/sql
库没有规定查询字符串中参数标记的任何特定格式,pq使用了postgres - native序号,像下面例子一样,相同的标记可以被重复使用,用于相同的参数:
// $2 使用了两次 都标记的值是64
rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1
OR age BETWEEN $2 AND $2 + 3`, "orange", 64)
操作时返回ID
pq不支持database/sql
的LastInsertId()
方法,所以当你需要插入(更新or删除)数据后获取自增长的id值时,你可以利用pg的RETURNING
语法:
var userid int
err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age)
VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid)
插入时存在更新
在数据看操作时,很多时候时候会存在唯一冲突,主键冲突等等,而我们又是需要在冲突时更新数据或者其他操作,这时我们可以这样:
// 其中name是唯一的,当name冲突时,更新其他字段
err := db.Exec(`INSERT INTO users(name,favorite_fruit,age)
VALUES($1, $2, $3)
ON CONFLICT (name) DO UPDATE
SET favorite_fruit=$2,
age=$3`)
// 当然,有时候你有条件更新
err := db.Exec(`INSERT INTO users(name,favorite_fruit,age)
VALUES($1, $2, $3)
ON CONFLICT (name) DO UPDATE
SET favorite_fruit=$2
WHERE age > $4`)
// 你也可以什么都不做
err := db.Exec(`INSERT INTO users(name,favorite_fruit,age)
VALUES($1, $2, $3)
ON CONFLICT (name) DO NOTHING`)
只有单行数据简化代码
这个其实上面就用到了,就是queryRow
。当你确定只取一行数据的时候你可以使用该函数。但是需要注意的是:当你查询的数据为空的时候,他会返回sql.ErrNoRaw
错误。
var count int
err := db.QueryRow(`SELECT count(*) FROM users`).Scan(&count)
if err != nil {
if err == sql.ErrNoRaw {
count = 0
...
}
...
}
结果集中空值处理
在查询的时候,有时候难以保证字段一定有值,如果为空,在scan
的时候就会报错,为了解决这种情况,我们可以使用下面这些来代替可能为空的字段。
--- 字符串 sql.NullString
--- bool sql.NullBool
--- int sql.NullInt64
--- float sql.NullFloat64
--- timestamp pq.NullTime
这里前面4个go驱动带的,后面是pq库带的。如果你还需要其他类型的,你可以自定义,只要实现Scanner
接口就OK了。
查询时需要嵌入数组
在使用pg语句的时候我们常用到WHERE xxx IN ('XXX','XXX'...)
这样的IN
数组操作,在go中也有对应的操作。
// 查找数组中对应id的所有人名
ids := []int64{12,16,33,55}
rows,err := db.Query(`SELECT name FROM users WHERE id=ANY($1),pq.Int64Array(ids))
...
当然其他类型对应的数组驱动也有
pq.BoolArray
pq.ByteaArray
pq.StringArray
pq.Float64Array
结果集中数组处理
同上,用到上面pq中的数组
var ids := pq.Int64Array{}
err := db.QueryRow(`SELECT array_agg(id) FROM users WHERE "age" > $1`,18).Scan(&ids)
...