文章目录

Go-MySQL(四)XORM

XORM介绍

xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。xorm的目标并不是让你完全不去学习SQL,我们认为SQL并不会为ORM所替代,但是ORM将可以解决绝大部分的简单SQL需求,XORM同时支持原始SQL和ORM操作

安装:

go get xorm.io/xorm

使用

创建orm引擎

所有操作均需要事先创建并且配置ORM引擎才能进行。XXORM支持两种ORM引擎:

  • Engine:用于对单个数据库进行操作,可以同时存在多个Engine引擎,一个Engine一般只对应一个数据库。
  • Engine Group:用于对数据库集群进行操作

创建engine:

var engie *xorm.Engine

// 创建orm引擎
func CreateEngine() {
engie,_ = xorm.NewEngine("mysql","root:123@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=True")
// 控制台打印SQL
engie.ShowSQL(true)
// 设置连接池参数 - 最大空闲连接
engie.SetMaxIdleConns(10)
// 设置连接池参数 - 最大连接数
engie.SetMaxOpenConns(20)
}

创建engineGroup:

var engieGroup *xorm.EngineGroup
// 创建连接组
func CreateEngineGroup() {
dbs := []string{
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",// 第一个默认是master
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",// 第二个开始slave
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",
}
engieGroup,_ = xorm.NewEngineGroup("postgres",dbs)
fmt.Println("master数据库:",engieGroup.Master())
fmt.Println("slave数据库:",engieGroup.Slaves())
}

定义数据模型

xorm支持将一个struct映射为数据库中对应的一张表

名称映射规则:主要处理struct名和表名,struct字段名和表字段名的映射

  • SnakeMapper:支持struct为驼峰式命名,表结构为下划线命名之间的转换,这个是默认的Maper;
  • SameMapper 支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名;
  • GonicMapper 和SnakeMapper很类似,但是对于特定词支持更好,比如ID会翻译成id而不是i_d。
// 修改名称映射规则
engie.SetMapper(names.SnakeMapper{})

字段定义:定义方法和Gorm类似,也是采用标签的形式定义,标签之间空格隔开

`xorm:标签A 标签B `

创建表xorm_user

// 定义数据模型
type XormUser struct {
Id int64 `xorm:"bigint pk autoincr comment('主键id')"` // pk:主键 autoincr: 自增 comment('注释'):字段注释
Name string `xorm:"varchar(25) notnull index('idx_name') comment('姓名')"` // notnull:非空约束 index('索引名'):定义普通索引
Age int32 `xorm:"int notnull comment('年龄')"`
Email string `xorm:"varchar(255) notnull unique('uniq_email') comment('邮箱')"` // unique('唯一索引名'):定义唯一索引,名字相同字段的则组合成联合唯一索引
Desc string `xorm:"-"` // - 不参与数据读写
CreateTime time.Time `xorm:"datetime notnull created"` // created:数据在插入时自动赋值为当前时间
UpdateTime time.Time `xorm:"datetime notnull updated"` // updated:数据在Insert或Update时自动赋值为当前时间
}

定义好数据模型struct后调用engine相关方法创建表

// 创建表
func CreateTableByEngine() {
if flag,_:= engie.IsTableExist(XormUser{});flag{
fmt.Println("已存在该表")
}else{
err1 := engie.CreateTables(XormUser{})
if err1 == nil{
fmt.Println("表创建成功")
// 创建索引。根据标签创建
engie.CreateIndexes(XormUser{})
engie.CreateUniques(XormUser{})
return
}
fmt.Println("标签创建失败:",err1)
}
}

控制台输出建表sql:

Go-MySQL(四)XORM_数据

Go-MySQL(四)XORM_数据_02

数据更新

数据插入

插入数据使用Insert方法,Insert方法的参数可以是一个或多个Struct的指针,一个或多个Struct的Slice的指针。

如果传入的是Slice并且当数据库支持批量插入时,Insert会使用批量插入的方式进行插入。

插入一条数据:使用Inert()或者InsertOne()

// 数据插入
func XormInsert() {
user := XormUser{
Name: "user1",
Age: 1,
Email: "123@qq.com",
}
rows,err := engie.Insert(user)
if err != nil{
fmt.Println("插入失败")
}
fmt.Println("插入",rows,"条数据")
}

Go-MySQL(四)XORM_sql_03

INSERT INTO `xorm_user` (`name`,`age`,`email`,`create_time`,`update_time`) VALUES (?,?,?,?,?) [user1 1 123@qq.com 2021-04-29 01:52:20 2021-04-29 01:52:20]

批量插入:传入结构体切片的指针即可

// 批量插入
func XormInsert() {
user2 := XormUser{
Name: "user2",
Age: 2,
Email: "124@qq.com",
}
user3 := XormUser{
Name: "user3",
Age: 3,
Email: "125@qq.com",
}
userSlice := []XormUser{user2,user3}
rows,err := engie.Insert(&userSlice)
if err != nil{
fmt.Println("插入失败")
}
fmt.Println("插入",rows,"条数据")
}

Go-MySQL(四)XORM_sql_04

xorm采用批量插入的方式完成数据插入而不是两个insert sql

INSERT INTO `xorm_user` (`name`,`age`,`email`,`create_time`,`update_time`) VALUES (?, ?, ?, ?, ?),(?, ?, ?, ?, ?) [user2 2 124@qq.com 2021-04-29 01:56:38 2021-04-29 01:56:38 user3 3 125@qq.com 2021-04-29 01:56:38 2021-04-29 01:56:38]

数据删除

数据删除通过Delete函数实现

func XormDelete()  {

// engie.ID(3).Delete(new(XormUser)) // 指定id删除
rows,err := engie.Where("name = ?","new").Delete(new(XormUser)) // 通过where指定条件删除
// DELETE FROM `xorm_user` WHERE (name = ?) [new]
if err != nil{
fmt.Println("删除失败,",err)
}
fmt.Println("删除了",rows,"条数据")
}

数据更新

更新数据使用Update方法,Update方法的第一个参数为需要更新的内容,可以为一个结构体指针或者一个Map[string]interface{}类型。当传入的为结构体指针时,只有非空和非0的field才会被作为更新的字段。当传入的为Map类型时,key为数据库Column的名字,value为要更新的内容。

// 数据更新
func XormUpdate() {
user3 := XormUser{
Id: 3,
Name: "new",
Age: 33,
}
// 1.可以使用where来指定更新条件 UPDATE `xorm_user` SET `name` = ?, `age` = ?, `update_time` = ? WHERE (id = ? and age = ?) [new 33 2021-04-29 02:25:04 3 33]
rows,err := engie.Where("id = ? and age = ?",user3.Id,user3.Age).Update(user3)
// 2.通过Cols()指定需要更新的列 UPDATE `xorm_user` SET `age` = ?, `update_time` = ? WHERE `id`=? [33 2021-04-29 02:24:46 3]
// rows,err := engie.ID(user3.Id).Cols("age").Update(user3)
// 3.传入map,指定多列需要修改的值,map方式需要指定表名 UPDATE `xorm_user` SET `age` = ?, `name` = ?, `update_time` = ? WHERE `id`=? [0 map 2021-04-29 02:24:15 3]
// rows,err := engie.Table(new(XormUser)).ID(user3.Id).Update(map[string]interface{}{"age":0,"name":"map"})
if err != nil{
fmt.Println("更新失败,",err)
}
fmt.Println("更新了",rows,"条数据")
}

第一种方法只有非nil非0的参数才会被更新,所以有第二第三种方法

数据查询

查询条件方法:

// 查询
func XormSelect() {
// 主键查询
var u XormUser
// var us []XormUser
// 1,主键查询 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE `id`=? LIMIT 1
// hasRec, err := engie.ID(2).Get(&u)

// 2,条件查询 where SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE (age = ? and email = ?) LIMIT 1
// hasRec,err := engie.Where("age = ? and email = ?",2,"124@qq.com").Get(&u)

// 3,Find()查多条数据,Get()查一条数据,OrderBy()排序 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE (age > ?) ORDER BY age desc
// err := engie.Where("age > ?",0).OrderBy("age desc").Find(&us)

// 4,In查询 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE `age` IN (?,?) [1 2]
//err := engie.In("age",[]int{1,2}).Find(&us)

// 5,只查询某些字段 SELECT `name` FROM `xorm_user` WHERE `id`=? LIMIT 1
_,err := engie.Cols("name").ID(1).Get(&u)
// 6,查数目 SELECT count(*) FROM `xorm_user` WHERE (age > ?) AND `name`=? [0 updateName] Count方法的参数为struct的指针并且成为查询条件。
total,_ := engie.Where("age > ?",0).Count(&u)
if err != nil {
fmt.Println("数据查询失败,", err)
}
fmt.Println("查到的数据:", total)
}

事务操作

和gorm不同的是,需要先构造session对象

// 事务处理
func XormTX() {
// 1,先创建session
session := engie.NewSession()
// 2.开启事务
session.Begin()
// 事务操作
// 3.提交事务
session.Commit()
// 抛异常则需要回滚事务
session.Rollback()
}

完整代码

package go_mysql

import (
"fmt"
"time"
"xorm.io/xorm"
"xorm.io/xorm/names"
)

var engie *xorm.Engine
var err error
// 创建orm引擎
func CreateEngine() {
engie,err = xorm.NewEngine("mysql","root:123@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=True")
if err != nil{
fmt.Println("链接失败:",err)
}
// 控制台打印SQL
engie.ShowSQL(true)
// 设置连接池参数 - 最大空闲连接
engie.SetMaxIdleConns(10)
// 设置连接池参数 - 最大连接数
engie.SetMaxOpenConns(20)
// 修改名称映射规则
engie.SetMapper(names.SnakeMapper{})
}

var engieGroup *xorm.EngineGroup
// 创建连接组
func CreateEngineGroup() {
dbs := []string{
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",// 第一个默认是master
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",// 第二个开始slave
"postgres://postgres:root@localhost:5432/test?sslmode=disable;",
}
engieGroup,_ = xorm.NewEngineGroup("postgres",dbs)
fmt.Println("master数据库:",engieGroup.Master())
fmt.Println("slave数据库:",engieGroup.Slaves())
}
// 定义数据模型
type XormUser struct {
Id int64 `xorm:"bigint pk autoincr comment('主键id')"` // pk:主键 autoincr: 自增 comment('注释'):字段注释
Name string `xorm:"varchar(25) notnull index('idx_name') comment('姓名')"` // notnull:非空约束 index('索引名'):定义普通索引
Age int32 `xorm:"int notnull comment('年龄')"`
Email string `xorm:"varchar(255) notnull unique('uniq_email') comment('邮箱')"` // unique('唯一索引名'):定义唯一索引,名字相同字段的则组合成联合唯一索引
Desc string `xorm:"-"` // - 不参与数据读写
CreateTime time.Time `xorm:"datetime notnull created"` // created:数据在插入时自动赋值为当前时间
UpdateTime time.Time `xorm:"datetime notnull updated"` // updated:数据在Insert或Update时自动赋值为当前时间
}

// 创建表
func CreateTableByEngine() {
if flag,_:= engie.IsTableExist(XormUser{});flag{
fmt.Println("已存在该表")
}else{
err1 := engie.CreateTables(XormUser{})
if err1 == nil{
fmt.Println("表创建成功")
// 创建索引。根据标签创建
engie.CreateIndexes(XormUser{})
engie.CreateUniques(XormUser{})
return
}
fmt.Println("标签创建失败:",err1)
}
}

// 数据插入
func XormInsertOne() {
user := XormUser{
Name: "user1",
Age: 1,
Email: "123@qq.com",
}
rows,err := engie.Insert(user)
if err != nil{
fmt.Println("插入失败")
}
fmt.Println("插入",rows,"条数据")
}

// 批量插入
func XormInsert() {
user2 := XormUser{
Name: "user2",
Age: 2,
Email: "124@qq.com",
}
user3 := XormUser{
Name: "user3",
Age: 3,
Email: "125@qq.com",
}
userSlice := []XormUser{user2,user3}
rows,err := engie.Insert(&userSlice)
if err != nil{
fmt.Println("插入失败")
}
fmt.Println("插入",rows,"条数据")
}

// 数据更新
func XormUpdate() {
user3 := XormUser{
Id: 3,
Name: "new",
Age: 33,
}
// 1.可以使用where来指定更新条件 UPDATE `xorm_user` SET `name` = ?, `age` = ?, `update_time` = ? WHERE (id = ? and age = ?) [new 33 2021-04-29 02:25:04 3 33]
rows,err := engie.Where("id = ? and age = ?",user3.Id,user3.Age).Update(user3)
// 2.通过Cols()指定需要更新的列 UPDATE `xorm_user` SET `age` = ?, `update_time` = ? WHERE `id`=? [33 2021-04-29 02:24:46 3]
// rows,err := engie.ID(user3.Id).Cols("age").Update(user3)
// 3.传入map,指定多列需要修改的值,map方式需要指定表名 UPDATE `xorm_user` SET `age` = ?, `name` = ?, `update_time` = ? WHERE `id`=? [0 map 2021-04-29 02:24:15 3]
// rows,err := engie.Table(new(XormUser)).ID(user3.Id).Update(map[string]interface{}{"age":0,"name":"map"})
if err != nil{
fmt.Println("更新失败,",err)
}
fmt.Println("更新了",rows,"条数据")
}

// 数据删除
func XormDelete() {

// engie.ID(3).Delete(new(XormUser)) // 指定id删除
rows,err := engie.Where("name = ?","new").Delete(new(XormUser)) // 通过where指定条件删除
// DELETE FROM `xorm_user` WHERE (name = ?) [new]
if err != nil{
fmt.Println("删除失败,",err)
}
fmt.Println("删除了",rows,"条数据")
}

// 查询
func XormSelect() {
// 主键查询
var u XormUser
// var us []XormUser
// 1,主键查询 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE `id`=? LIMIT 1
// hasRec, err := engie.ID(2).Get(&u)

// 2,条件查询 where SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE (age = ? and email = ?) LIMIT 1
// hasRec,err := engie.Where("age = ? and email = ?",2,"124@qq.com").Get(&u)

// 3,Find()查多条数据,Get()查一条数据,OrderBy()排序 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE (age > ?) ORDER BY age desc
// err := engie.Where("age > ?",0).OrderBy("age desc").Find(&us)

// 4,In查询 SELECT `id`, `name`, `age`, `email`, `create_time`, `update_time` FROM `xorm_user` WHERE `age` IN (?,?) [1 2]
//err := engie.In("age",[]int{1,2}).Find(&us)

// 5,只查询某些字段 SELECT `name` FROM `xorm_user` WHERE `id`=? LIMIT 1
_,err := engie.Cols("name").ID(1).Get(&u)
// 6,查数目 SELECT count(*) FROM `xorm_user` WHERE (age > ?) AND `name`=? [0 updateName] Count方法的参数为struct的指针并且成为查询条件。
total,_ := engie.Where("age > ?",0).Count(&u)
if err != nil {
fmt.Println("数据查询失败,", err)
}
fmt.Println("查到的数据:", total)
}

// 事务处理
func XormTX() {
// 1,先创建session
session := engie.NewSession()
// 2.开启事务
session.Begin()
// 事务操作
// 3.提交事务
session.Commit()
// 抛异常则需要回滚事务
session.Rollback()
}

func TestXorm() {
CreateEngine()
XormSelect()
}