3

2.快速使用的正确姿势 · gorose文档2.0 · 看云

 1 year ago
source link: https://www.kancloud.cn/fizz/gorose-2/1135836
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

2.快速使用的正确姿势

一. talk is cheap, show me your code

DROP TABLE IF EXISTS "users";
CREATE TABLE "users" (
	 "uid" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
	 "name" TEXT NOT NULL,
	 "age" integer NOT NULL
);

INSERT INTO "users" VALUES (1, 'gorose', 18);
INSERT INTO "users" VALUES (2, 'goroom', 18);
INSERT INTO "users" VALUES (3, 'fizzday', 18);

1. 查询操作

原生sql查询

package main

import (
	"fmt"
	"github.com/gohouse/gorose/v2"
	_ "github.com/mattn/go-sqlite3"
)

var err error
var engin *gorose.Engin

func init() {
    // 全局初始化数据库,并复用
    // 这里的engin需要全局保存,可以用全局变量,也可以用单例
    // 配置&gorose.Config{}是单一数据库配置
    // 如果配置读写分离集群,则使用&gorose.ConfigCluster{}
    // mysql Dsn示例 "root:root@tcp(localhost:3306)/test?charset=utf8&parseTime=true"
	engin, err = gorose.Open(&gorose.Config{Driver: "sqlite3", Dsn: "./db.sqlite"})
}
func DB() gorose.IOrm {
	return engin.NewOrm()
}
func main() {
	// 这里定义一个变量db, 是为了复用db对象, 可以在最后使用 db.LastSql() 获取最后执行的sql
	// 如果不复用 db, 而是直接使用 DB(), 则会新建一个orm对象, 每一次都是全新的对象
	// 所以复用 db, 一定要在当前会话周期内
	db := DB()
	res,err := db.Query("select * from users limit 2")
    fmt.Println(res,err)
}

结果集绑定到map

type user gorose.Data

func (u *user) TableName() string {
	return "users"
}
func main() {
	// 查询一条
	// 这里的对象是map, 所以需要初始化(var u = user{}), 不能像struct那样, 可以直接 `var u Users`
	var u = user{}
	// 查询数据并绑定到 user{} 上
	err = db.Table(&u).Fields("uid,name,age").Where("age",">",0).OrderBy("uid desc").Select()
	if err!=nil {
		fmt.Println(err)
	}
	fmt.Println(u, u["name"])
	fmt.Println(db.LastSql())
	// 查询多条
	// 查询数据并绑定到 []user{} 上, 这里复用了 db 及上下文条件参数
	// 如果不想复用,则可以使用DB()就会开启全新会话,或者使用db.Reset()
	// db.Reset()只会清除上下文参数干扰,不会更换链接,DB()则会更换链接
	var u2 = make([]user,0)
	err = db.Limit(10).Offset(1).Select()
	fmt.Println(u2)
	
	// 统计数据
	var count int64
	// 这里reset清除上边查询的参数干扰, 可以统计所有数据, 如果不清楚, 则条件为上边查询的条件
	// 同时, 可以新调用 DB(), 也不会产生干扰
	count,err = db.Reset().Count()
	// 或
	count, err = DB().Table(&u).Count()
	fmt.Println(count, err)
}

绑定到struct

type Users struct {
    Uid int64 `gorose:"uid"`
    Name string `gorose:"name"`
    Age int64 `gorose:"age"`
}
var u Users
err := DB().Table(&u).Select()

如果不知道数据库字段类型对应golang的类型,可以参考文末的"附录"

如果觉得手动定义struct太麻烦, 可以使用 https://github.com/gohouse/converter 这个包,一键生成迁移struct

table传入string

res,err := DB().Table("users").First()
fmt.Println(res["Name"])
res2,err := DB().Table("users").Limit(5).Get()
fmt.Println(res2)

注意: 当传入的table是string时,需要调用Get()First()才能取到数据, 同时需要多接收一个参数res存放查询结果,其中First()返回一条数据map[string]interface{},Get()返回多条数据[]map[string]interface{}, 快捷类型为 gorose.Data.
使用Get()First()方法, 一定要接收返回的第一个参数为结果,使用Select()则为绑定结果,为了减少内存占用,只要使用了Get()First(),即使传入的是struct绑定对象,也不会有数据,只能通过返回的第一个参数接收结果集

需要说明的东西,基本都在注释里了

2.增删改

DB().Table(&user).Data(gorose.Data{"name":"fizzday"}).Insert()
// 如果传入的是struct, 则可以不用指定Table(), orm会根据传入的struct,解析出table. update()操作类似
DB().Insert(&Users{Name:"fizz",Age:18})

DB().Table(&user).Where("uid",1).Delete()

3.事务操作

一键事务, 自动回滚和提交, 我们只需要关注业务即可

db:= DB()
err := db.Transaction(
    // 第一个业务
	func(db IOrm) error {
		_,err := db.Where("uid",1).Update(&Data{"name":"gorose2"})
		if err!=nil {
			return err
		}
		_,err = db.Insert(&Data{"name":"gorose2"})
		if err!=nil {
			return err
		}
		return nil
	}, 
    // 第二个业务
	func(db IOrm) error {
		_,err := db.Where("uid",1).Delete()
		if err!=nil {
			return err
		}
		_,err = db.Insert(&Data{"name":"gorose2"})
		if err!=nil {
			return err
		}
		return nil
	})
db:= DB()
db.Begin()
err :=myfunc()
if err!=nil {
    db.Rollback()
}
db.Commit()

二. 废话一下使用技巧

  1. 全局使用engin的示例

使用全局变量

var Engin *gorose.Engin
Engin = gorose.Open("xxxxx")

或使用单例

var once sync.Once
var engin *gorose.Engin
func NewGorose() *gorose.Engin {
    once.Do(func(){
        engin = gorose.Open("xxxxx")
    })
    return engin
}
  1. 不复用会话时可以有两种用法

直接使用全局engin

err := NewGorose().NewOrm().Table(&user).Select()

或封装一个DB()函数

func DB() gorose.IOrm {
	return engin.NewOrm()
}
err := DB().Table(&user).Select()
  1. 复用会话参见代码示例和对应注释, 另外, 事务一定要复用会话,确保用的是同一个链接. 当然不需要自己手动db.Reset(),系统会在检测到事务时,自动Reset(), 所以使用事务, 每一次都需要传入全部的上下文参数

  2. 关于绑定对象: 如果传入的slice, 如: []struct, []map这种结构, 则会取多条数据. 如果传入不是slice, 则只会取一条数据, 因为取多条毫无意义, 只会是后一条覆盖前一条, 最终返回的还是最后一条

// key为mysql的字段类型, value为golang的数据类型
var typeForMysqlToGo = map[string]string{
	"int":                "int",
	"integer":            "int",
	"tinyint":            "int",
	"smallint":           "int",
	"mediumint":          "int",
	"bigint":             "int64",
	"int unsigned":       "int",
	"integer unsigned":   "int",
	"tinyint unsigned":   "int",
	"smallint unsigned":  "int",
	"mediumint unsigned": "int",
	"bigint unsigned":    "int64",
	"bit":                "int",
	"bool":               "bool",
	"enum":               "string",
	"set":                "string",
	"varchar":            "string",
	"char":               "string",
	"tinytext":           "string",
	"mediumtext":         "string",
	"text":               "string",
	"longtext":           "string",
	"blob":               "string",
	"tinyblob":           "string",
	"mediumblob":         "string",
	"longblob":           "string",
	"date":               "time.Time", // time.Time or string
	"datetime":           "time.Time", // time.Time or string
	"timestamp":          "time.Time", // time.Time or string
	"time":               "time.Time", // time.Time or string
	"float":              "float64",
	"double":             "float64",
	"decimal":            "float64",
	"binary":             "string",
	"varbinary":          "string",
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK