https://github.com/jmoiron/sqlx
文档甚好, 基本的 连接和使用都有 , 除了 insert 外最经常使用到的就是 select one 这些比 原生的sql api 好用太多 封装了 连接 建立关闭 等操作
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
"github.com/jmoiron/sqlx"
)
var schema = `
CREATE TABLE person (
first_name text,
last_name text,
email text
);
CREATE TABLE place (
country text,
city text NULL,
telcode integer
)`
type Person struct {
FirstName string `db:"first_name"`
LastName string `db:"last_name"`
Email string
}
type Place struct {
Country string
City sql.NullString
TelCode int
}
func main() {
// this Pings the database trying to connect, panics on error
// use sqlx.Open() for sql.Open() semantics
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
if err != nil {
log.Fatalln(err)
}
// exec the schema or fail; multi-statement Exec behavior varies between
// database drivers; pq will exec them all, sqlite3 won't, ymmv
db.MustExec(schema)
tx := db.MustBegin()
tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "[email protected]")
tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "[email protected]")
tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1")
tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852")
tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65")
// Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person
tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "[email protected]"})
tx.Commit()
// Query the database, storing results in a []Person (wrapped in []interface{})
people := []Person{}
db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")
jason, john := people[0], people[1]
fmt.Printf("%#v\n%#v", jason, john)
// Person{FirstName:"Jason", LastName:"Moiron", Email:"[email protected]"}
// Person{FirstName:"John", LastName:"Doe", Email:"[email protected]"}
// You can also get a single result, a la QueryRow
jason = Person{}
err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
fmt.Printf("%#v\n", jason)
// Person{FirstName:"Jason", LastName:"Moiron", Email:"[email protected]"}
// if you have null fields and use SELECT *, you must use sql.Null* in your struct
places := []Place{}
err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC")
if err != nil {
fmt.Println(err)
return
}
usa, singsing, honkers := places[0], places[1], places[2]
fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers)
// Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
// Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
// Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
// Loop through rows using only one struct
place := Place{}
rows, err := db.Queryx("SELECT * FROM place")
for rows.Next() {
err := rows.StructScan(&place)
if err != nil {
log.Fatalln(err)
}
fmt.Printf("%#v\n", place)
}
// Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
// Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
// Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
// Named queries, using `:name` as the bindvar. Automatic bindvar support
// which takes into account the dbtype based on the driverName on sqlx.Open/Connect
_, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`,
map[string]interface{}{
"first": "Bin",
"last": "Smuth",
"email": "[email protected]",
})
// Selects Mr. Smith from the database
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"})
// Named queries can also use structs. Their bind names follow the same rules
// as the name -> db mapping, so struct fields are lowercased and the `db` tag
// is taken into consideration.
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
}
成熟的项目没有不使用连接池的, 节省打开关闭的系统开销
package mysqler
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"log"
)
var DbInit = DbWorkerConnect{}
type DbWorkerConnect struct {
Conn *sqlx.DB
}
func NewDbWorkerConnect() {
dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v", config.GlobalConfig.MySQLUserName, config.GlobalConfig.MySQLPassword, config.GlobalConfig.MySQLHost, config.GlobalConfig.MySQLPort, config.GlobalConfig.MySQLDbName)
dataSourceName = dataSourceName + "?parseTime=true&loc=Asia%2FShanghai&charset=utf8"
db, err := sqlx.Connect("mysql", dataSourceName)
if err != nil {
log.Fatalln(err)
}
db.SetMaxIdleConns(0) // 设置理想最大连接数
DbInit.Conn = db
}
在进行初始化 了之后 在程序中就可以直接使用
mysqler.DbInit.Conn.Get(out, queryString)
type Demo struct {
Id string `json:"id"`
CreatedAt time.Time `json:"createdAt" db:"createdAt"`
ChangedAt time.Time `json:"changedAt" db:"changedAt"`
Timestamp int64 `json:"timestamp"`
}
原生的 sql 是说支持的
https://github.com/go-sql-driver/mysql/#installation
但是这里要注意 一定要在 数据库 连接的时候 使用相应的参数
dataSourceName = dataSourceName + "?parseTime=true&loc=Asia%2FShanghai&charset=utf8"
parseTime=true 这样才能获取到想要的数据格式
存入数据的时候 存成 北京时间
标签
FirstName string db:"first_name"
当有两个单词组合的时候一定要加上 db:"first_name"
标签的 不然读取不到
type Place struct {
Country string
City sql.NullString
TelCode int
}
当数据库中设计的字段 默认是 NULL 的时候会用到的。
获取具体的值
Place .city.String
插入的时候 会使用 这样的
tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1")
读取的时候 需要什么字段 取什么字段 这样有时候 也好排查错误
同时对于性能的影响也是有的
var opts []modelBaseData.Place
queryString := fmt.Sprintf("select country ,city from %v where isValid =%v and parentId in (%v)order by opNo asc ", tools.DBEvalQuestion, tools.ValidEvalQuestionTrue, city)
err := classObj.Db.Conn.Select(&opts, queryString)
insertSql := fmt.Sprintf("insert into %v (id,"+
"createdAt,"+
"changedAt,"+
"timestamp,"+
"content,"+
"isValid) values (:id,"+
":createdAt,"+
":changedAt,"+
":timestamp,"+
":content,"+
":isValid)", tools.Demo)
struct 中 接受插入都是slice
state[]uint8 `json:"isValid" db:"state"`
插入的时候 要进行转化
tools.GetByteByInt(1)
func GetByteByInt(obj int) []byte {
d := []byte(string(obj))
return d
}
完整的插入语句
insertSql := fmt.Sprintf("insert into %v (id,"+
"createdAt,"+
"changedAt,"+
"timestamp,"+
"content,"+
"state) values (:id,"+
":createdAt,"+
":changedAt,"+
":timestamp,"+
":content,"+
":state)", tools.Demo)
obj.Id = tools.GetUUID()
obj.CreatedAt = tools.GetNowTimeBj()
obj.ChangedAt = tools.GetNowTimeBj()
obj.Timestamp = tools.GetNowTimeStamp()
obj.IsValid = tools.GetByteByInt(tools.ValidMatchTipTrue)
tx := DbInit.Db.Conn.MustBegin()
_, err := tx.NamedExec(insertSql, obj)
logs.PrintContextLog.Info(err)
err = tx.Commit()
update 语句
updateSql := fmt.Sprintf("update %v set "+
"changedAt = :changedAt,"+
"timestamp = :timestamp,"+
"state=:state"+
" where id=:id", tools.Demo)
queryString := fmt.Sprintf("select id from %v where id ='%v' and state= %v", "yang", theId, 1)
注意 表的名字不需要 加 引号
update 中的语句
updateSql := fmt.Sprintf("update %v set isValid=:isValid where id=:id", demo)
当条件 为string 的时候, 拼接 串
func GetSqlInString(s []string) string {
var temp []string
sCount := len(s)
if sCount == 0 {
return ""
}
for _, item := range s {
temp = append(temp, "'"+item+"'")
}
tempString := strings.Join(temp, ",")
return tempString
}
为int64 的 时候
func GetSqlInInt64(s []int64) string {
var temp []string
sCount := len(s)
if sCount == 0 {
return ""
}
for _, item := range s {
temp = append(temp, ""+strconv.FormatInt(item, 10)+"")
}
tempString := strings.Join(temp, ",")
return tempString
}
调用
parentsString := tools.GetSqlInString(obj)
queryString := fmt.Sprintf("select id from %v where state=%v and parentId in (%v)order by optionNo asc ", "demo", 1, parentsString)
字符串格式化语句
.... order by questionNo asc limit %v offset %v