Golang学习笔记

Posted 流光之中

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang学习笔记相关的知识,希望对你有一定的参考价值。

Go

简介

C/C++ 快执行速度-----Golang----Python/Ruby

Go优势

  • 编译型语言,运行速度快,但有动态语言的部分特性,开发效率高
  • 语言层面支持并发
  • 内置Runtime,GC
  • 内嵌C支持,可直接引用C代码

1. hello world

package main

import (
	"fmt"
)
func main() {
	fmt.Println("Hello World!")
}

package: 包名

import: 导包

main函数:go程序的入口,与python,c++,java不同,go程序的main函数是不含参的,在控制台中输入的参数在org.Args()

方法:

func 函数名(参数列表)(返回值列表){
	//函数体
}

注意:函数题的左花括号必须在函数名后,不能另起一行

注释:同C++相同

//注释
/* 注释 */

2. 变量

关键字 25个

变量声明:

var [变量名] [类型]

多变量

var [变量名1,变量名2] [类型]

var x int
var x,y int
var(
	x int
	y int
)

变量初始化,类似于python,可自动推导类型 ,\':=\'操作符是声明并赋值操作

var x int =10
var x=10  //自动推导类型
x:=10	  //自动推导类型

变量赋值

var x int
x=1

var x,y,z int
x,y,z=1,2,3

i:=1
j:=2
i,j=j,i//交换

常量修饰符 const

字面量:程序中硬编码的常量

const x=1
const(
    x=1
    y=2
)

iota枚举 在常量声明中使用

常量声明可以使用iota常量生成器初始化,生成一组以相似规则初始化的常量,不用每行都写一遍初始化表达式,第一行为0,其他行为上一行+1

const(
    x=iota//0
    y=iota//1
    z=iota//2
)
//每遇到const,iota置0
const(
	x,y,z=iota,iota,iota//同一行不变
)
const(
	x=iota//0
	y="helloworld"
	z=iota//2
)

自定义类型

type Newtype int
const ( 
    T1 Newtype = iota // 0 
    T2                // 1 
    T3                // 2 
    T4                // 3 
)
//跳过一些值
type AudioOutput int
const ( 
    OutMute AudioOutput = iota // 0 
    OutMono                    // 1 
    OutStereo                  // 2 
    _ 
    _ 
    OutSurround                // 5 
)

通过表达式定义数量级

type ByteSize float64
const (
    _           = iota 
    KB ByteSize = 1 << (10 * iota) // 1 << (10*1)
    MB                                   // 1 << (10*2)
    GB                                   // 1 << (10*3)
    TB                                   // 1 << (10*4)
    PB                                   // 1 << (10*5)
    EB                                   // 1 << (10*6)
    ZB                                   // 1 << (10*7)
    YB                                   // 1 << (10*8)
)

3.基础数据类型

  • 整型
    int    uint
    int8    uint8
    int32    uint32
    int64    uint64
    uintptr 以存储指针的uint32或uint64整数
  • 浮点型
go    float32    float64
  • 布尔型
	bool
	var v bool
	v=1    //编译错误
	v=bool(1)    //编译通过
  • 字节型(uint8的别名,代表utf-8字符串的单个字节的值)
	byte
  • 字符型(代表单个unicode字符)
	rune
  • 字符串
	string
  • 复数
	complex64    complex128
	var x=1.0+2i complex64
    x=complex(1.0,2)

4. 格式化输出

fmt.Printf()输出格式字符串
格式 含义
%% 输出一个%字面量
%b 二进制
%c 字符型
%e 科学计数法,使用e(浮点数、复数)
%E 科学计数法,使用E(浮点数、复数)
%f 浮点数、复数
%g 以最为紧凑的方式输出(浮点数%e、%f、复数)
%G 以最为紧凑的方式输出(浮点数%E、%f、复数)
%o 八进制
%p 十六进制,前缀为0x,字母使用小写的a-f表示
%q 字符串或者字节切片[]byte,或者是以单引号括起来的数字
%t 布尔类型
%T 输出值得类型
%U Unicode表示法表示的整型码点
%v 使用默认格式输出的内置或者自定义类型的值
%x 十六进制a-f
%X 十六进制A-F

5. 类型转换

go语言类型转换只可以显式的进行

var x int
x=1
y:=float32(x)

6. 类型别名

type long int64
var x long=1000

7. 运算符

运算符
+
-
*
/
%
++ 没有前自增
-- 没有前自减
==
!=
||
&
|
^
<< 左移
>> 右移
=
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
& 取地址
* 指针取值

优先级

8. 流程控制

  • if语句
if a==0 {//条件表达式不写括号
   //code
}else{//左括号与else同行
    //code
}
if a:=0;b==0{//初始化;条件表达式
    //code
} else if b>1{
    //code
}
  • for语句
for i:=1;i<100;i++{
    //code
}
s:="abc"
for i :=range s{//range 支持string/array/slice/map
    fmt.Printf("%c\\n",s[i])
}
for _,i :=range s{//index,value
    fmt.Printf("%c\\n",i)
}
  • switch语句

    每个case语句默认带有break,需要执行多个case时,使用fallthrough强制执行后面语句

score:=100
switch score{
    case 100:
    	//code
    case 90:
    	//code
    	fallthrough
    case 60,70,80:
    	//code
    default:
    	//code
}
switch{//不写条件
    case score>=90:
    	//code
    default:
    	//code
}
switch score=60;{//初始化,但不写条件
    case score>=90:
    	//code
    default:
    	//code
}
  • break

    跳出当前循环

  • continue

    跳过本次循环

func my_fun{
    LABEL:
        for i:=0;i<100;i++{
            for{
                //code
                break LABEL//跳出所有循环
                continue LABEL//跳过for{}循环,外层for继续
            }
        }
}
  • goto

    跳转到当前函数内定义标签

func my_fun{
    LABEL:
        for i:=0;i<100;i++{
            for{
                //code
                goto LABEL//跳转至LABEL
            }
        }
}

9. 函数

func FuncName(/*参数列表*/) (o1 type1, o2 type2/*返回类型*/) {
    //code
    return v1, v2 //返回多个值
}

不定参数

func my_func(args ...int){//无返回值
    for _,arg:=range args{
        //code
    }
}

有返回值

func my_func() int{//返回值不命名
    for _,arg:=range args{
        //code
    }
}
func my_func()(value int){//返回值不命名
    for _,arg:=range args{
        //code
    }
}
func my_func() (int,int){//多返回值不命名
    for _,arg:=range args{
        //code
    }
}
func my_func()(value int,value2 ){//返回值不命名
    for _,arg:=range args{
        //code
    }
}
9.1 函数类型

Go中函数也是一种类型,可以作为函数的参数,有相同入参和出参的函数属于同一类型

type FuncType func()//声明函数类型,无参无返回值
type FuncType func1(int,int) int//声明函数类型,有参有返回值

func cal(a,b int,f FuncType)(res int){
    res=f(a,b)
    return
}

func add(a,b int) int {
    return a+b
}

func main(){
    res:=cal(1,1,add)
}
9.2 匿名函数

不要函数名的一种实现函数的方法

闭包:捕获同一作用域的变量,不管在何处调用闭包,都可以使用该变量,闭包存在,变量不会失效,闭包中的变量是引用,在闭包中改变变量会改变原来的值。

f:=func(){//无参匿名函数
	//code
}
f()

type FuncType func()
var f1 FuncType=f
f1()

f:=(){
    //code
}()//此处的()会使该匿名函数直接调用

f2:=func(a,b int) (res int){
    res=a+b
    return
}(1,1)//直接传参调用

10. 包权限

public: 包中成员首字母大写,包外可访问

private:包中成员首字母小写,仅包内访问

main包:

函数入口,且一个程序只有一个main,main()是程序的入口

main()和init()函数:

没有入参和出参。程序执行时会先执行init()再执行main(),且包中可包含任意个init()

如果一个包被多个包引用,则程序中只会导入一次

别名导包:

import (
    io "fmt" 
)

空白导包:空白标识符:_

import (
	_ "fmt" 
)

11. 指针

默认值:nil

. : 访问目标成员,不支持指针运算

&取地址,*取值

new(T):创建一个T类型的匿名变量,为T类型的新值分配并清零一块内存,返回*T

12. 数组

var a [10]int//[]内为长度,必须是常量,后面是数组类型
//遍历
for i := 0; i < 10; i++ {
    a[i] = i + 1
    fmt.Printf("a[%d] = %d\\n", i, a[i])
}
for i, v := range a {
    fmt.Println("a[", i, "]=", v)
}

相关函数:

len、cap:求长度

初始化:

a:=[3]int{1,2,3}
a:=[...]int{1,2,3}
a:=[5]int{2:10,3:10}
//二维
a:=[2][2]int{{1,2},{3,4}}
b:=[3]int{1,2}
var d [3]int
d=a

动态数组、切片:声明时方括号不添加长度

切片声明:

arr:=[]int{1,2,3}

var arr []int
arr=make([]int,2)//make 开辟空间
arr=make([]int,2,5)//make 开辟空间,第一个参数为切片长度,第二个参数为切片容量  

var arr []int=make([]int,3)

arr:=make([]int,3)//自动推导类型

切片的追加

append(arr,3)

切片扩容

向一个容量cap满的切片追加元素时,容量将增加2倍

13 Map

声明

var myMap=map[string]string

var myMap=map[string]string
myMap=make(map[string]string,10)

myMap:=make(map[string]string)

myMap:=map[string]string{
	\'1\':\'1\'
}

使用

//添加
myMap["1"]="1"
//遍历
for k,v := range myMap{
	//...
}
//删除
delete(myMap,"1")

14 结构体

type Book struct{
	title string
}

15 类的定义

//类名大写,其他包也可以访问
type Book struct{
    //属性名大写,公有属性
	Title string
}
//传参是一个类的拷贝,不会影响原来的对象
func (this Book) GetTitle(){
    return this.title
}
func (this Book) SetTitle(name string){
    this.title=name
}
//类的方法
//地址传参
func (this *Book) GetTitle(){
    return this.title
}
func (this *Book) SetTitle(name string){
    this.title=name
}

类的继承

type Math struct{
	Book//继承该类
	page int//新的属性
}
//重写方法
func (this *Math)GetTitle(){
	//...
}
//定义子类
math1:=Math{Book{"math1"},100}

var math1 Math
math1.Title="math1"

多态

//定义接口
type Book interface{
    getName()
}
//第一个子类
type Math struct{
    name string
}
func (this *Math)GetName(){
    //...
}
//第二个子类
type English struct{
    name string
}
func (this *English)GetName(){
    //...
}

var Book book
book=&Math("math1")
book.GetName()

interface空接口万能类型

//可以传入任何参数
func test(arg interface{}){
	fmt.Println("...")
}

16 断言机制

//判断arg是否为string类型
//第一个返回值为如果断言成立,具体的参数值
//第二个为断言是否成立
value,ok:=arg.(string)

变量的结构

变量的内置pair

func main(){
	tty,err:=os.OpenFile("/dev/tty",os.O_RDWR,0)
	var r io.Reader
	//r:pair<type:*os.File,value:"/dev/tty">
	r=tty
	
	var w io.Writer
	//w:pair<type:*os.File,value:"/dev/tty">
	w=r.(io.Reader)
	//此处仍然可以断言成功,内置pair没有变化
    w.Write([]byte("Hello!"))//往终端写
}

17 反射(reflect包)

//返回一个变量的值,为空时返回0
func ValueOf(i interface{})Value{
	//...
}
//返回一个变量的类型,为空时返回nil
func TypeOf(i interface{})Value{
	//...
}

结构体标签

//keyvalue结构
type Book struct{
	page int `info:"page",doc:"math"`
	name string `info:"math"\'`
}
//利用反射解析结构体标签
b:=&Book()
t=reflect.TypeOf(b).Elem()
for i:=0;i<t.NumField();i++{
	taginfo:=t.Field(i).Tag.get("info")
	taginfo:=t.Field(i).Tag.get("doc")
}

18 结构体标签转Json

package main

import (
	"encoding/json"
	"fmt"
)

type Book struct {
	Title string	`json:"title"`
	Page  int		`json:"page"`
}

func main() {
    //对象转json
	math := Book{"math", 100}
	jsonStr, err := json.Marshal(math)
	if err != nil {
		fmt.Println("json marshal error")
		return
	}
	fmt.Printf("%s\\n", jsonStr)
	//jsonStr:={"title":"math","page":100}
    //jsonz
	book1:=Book{}
	err=json.Unmarshal(jsonStr,&book1)
	if err!=nil{
		fmt.Println("json unmarshal error")
		return
	}
	fmt.Printf("%v", book1)
}

19 goroutine

创建协程

go func(){
    //...
    func(){
        //...
    }()
}()

go func(a int,b int)bool{
    return true
}(10,10)

goroutine之间通信

channel(管道)

//定义一个channel
c:=make(chan int)

go func(){
    //将一个整型发送至channel
    c<-100
}()
//从管道中读取数据
num:=<-c

无缓冲channel

管道中只能存在一个数据

只有读端或者只有写端,将会导致阻塞

ch:=make(chan int)
//管道容量为1
//len(ch)=0,cap(ch)=1

有缓冲channel

管道中可存储多个数据

当管道为空,从管道读取会导致阻塞,管道满,往管道写数据也会导致阻塞

ch:=make(chan int,10)
//管道容量为10
//len(ch)=0,cap(ch)=10

关闭channel

当确定没有数据发送了,显式地关闭channel,关闭channel后仍然可以接收数据,直到管道中没有数据

close(chan)
//data为channel中的数据,ok为true表示channel没有关闭,或管道中还有数据,false表示channel已经关闭且没有数据
//关闭后再向channel发送数据会报错
data,ok:=<-chan
//这里的if语句会先执行前面一条语句,并将ok作为条件表达式
if data,ok:=<-chan;ok{
    //...
}

channel与range

//使用range从channel(channel没有关闭时)中读取数据
for data:=range chan{
	//...
}
//等同于
for{
    if data,ok:=<-chan;ok{
        //...
    }else{
        break
    }
}

channel与select

select:单流程下一个go只能监控一个channel的状态,select可以同时监控多个channel的状态

select{
    case <-chan1:
    	//...
    case <-chan2:
    	//...
    default:
    	//...
}

20 Go Modules

GOPATH:

  • 无版本控制
  • 无法同步一致第三方版本号
  • 无法指定当前项目引用的第三方版本号

学习笔记Golang之Gorm学习笔记

一、模型定义

1. 模型定义

模型是标准的 struct,由 Go 的基本数据类型、实现了 ScannerValuer 接口的自定义类型及其指针或别名组成,如:

type User struct 
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivedAt    sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time

gorm默认情况下约定使用结构体的名字作为表名,结构体字段名作为列名,使用ID作为主键。

gorm.Model是gorm定义的一个结构体,它包含了几个常见的字段名。

// gorm.Model 的定义
type Model struct 
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`

2. 字段级权限控制

对于可导出的字段,可以使用结构体标签来控制字段的权限。

type User struct 
  Name string `gorm:"<-:create"` // 允许读和创建
  Name string `gorm:"<-:update"` // 允许读和更新
  Name string `gorm:"<-"`        // 允许读和写(创建和更新)
  Name string `gorm:"<-:false"`  // 允许读,禁止写
  Name string `gorm:"->"`        // 只读(除非有自定义配置,否则禁止写)
  Name string `gorm:"->;<-:create"` // 允许读和写
  Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)
  Name string `gorm:"-"`  // 读写操作均会忽略该字段

3. 创建 / 更新时间追踪

GORM 约定使用 CreatedAtUpdatedAt 追踪创建 / 更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充当前时间。

type User struct 
  CreatedAt time.Time // 在创建时,如果该字段值为零值,则使用当前时间填充
  UpdatedAt int       // 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
  Updated   int64 `gorm:"autoUpdateTime:nano"` // 使用时间戳填纳秒数充更新时间
  Updated   int64 `gorm:"autoUpdateTime:milli"` // 使用时间戳毫秒数填充更新时间
  Created   int64 `gorm:"autoCreateTime"`      // 使用时间戳秒数填充创建时间

4. 嵌入结构体

当一个结构体中嵌入了一个匿名结构体时,匿名结构体的字段也被认为是父结构体的字段。而如果是嵌入了一个普通结构体时,可以使用embedded标签来将其嵌入:

type Author struct 
    Name  string
    Email string


type Blog struct 
  ID      int
  Author  Author `gorm:"embedded"`
  Upvotes int32

// 等效于
type Blog struct 
  ID      int64
  Name    string
  Email   string
  Upvotes int32

5. 字段标签

gorm支持以下tag,tag名大小写不敏感,但建议使用驼峰命名。

标签名说明
column指定 db 列名
type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INSTREMENT
size指定列大小,例如:size:256
primaryKey指定列为主键
unique指定列为唯一
default指定列的默认值
precision指定列的精度
scale指定列大小
not null指定列为 NOT NULL
autoIncrement指定列为自动增长
embedded嵌套字段
embeddedPrefix嵌入字段的列名前缀
autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime创建 / 更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
uniqueIndex与 index 相同,但创建的是唯一索引
check创建检查约束,例如 check:age > 13,查看 约束 获取详情
<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
->设置字段读的权限,->:false 无读权限
-忽略该字段,- 无读写权限

二、连接数据库

以连接MySQL数据库为例。

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

func main() 
  // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
  dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config)

连接数据库的高级配置

db, err := gorm.Open(mysql.New(mysql.Config    
  DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
  DefaultStringSize: 256, // string 类型字段的默认长度
  DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
  DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
  DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
  SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
), &gorm.Config)

gorm允许通过一个现有的数据库连接来初始化*gorm.DB

import (
  "database/sql"
  "gorm.io/gorm"
)

sqlDB, err := sql.Open("mysql", "mydb_dsn")
gormDB, err := gorm.Open(mysql.New(mysql.Config
  Conn: sqlDB,
), &gorm.Config)

连接池

sqlDB, err := db.DB()

// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)

三、CRUD接口

1. 创建记录

(1) 创建记录

user := UserName: "Jinzhu", Age: 18, Birthday: time.Now()

result := db.Create(&user) // 通过数据的指针来创建

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

(2) 用指定字段创建记录

创建记录并更新给出的字段。用Select,指定你想从数据库中检索出的字段

db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建记录并更新未给出的字段

db.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

(3) 批量插入

要有效地插入大量记录,请将一个 slice 传递给 Create 方法。 将切片数据传递给 Create 方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

var users = []UserName: "jinzhu1", Name: "jinzhu2", Name: "jinzhu3"
db.Create(&users)

for _, user := range users 
  user.ID // 1,2,3


使用 CreateInBatches 创建时,你还可以指定创建的数量

var users = []Username: "jinzhu_1", ...., Name: "jinzhu_10000"

db.CreateInBatches(users, len(users))

(4) 根据map创建

GORM 支持根据 map[string]interface[]map[string]interface 创建记录,例如:

db.Model(&User).Create(map[string]interface
  "Name": "jinzhu", "Age": 18,
)

// batch insert from `[]map[string]interface`
db.Model(&User).Create([]map[string]interface
  "Name": "jinzhu_1", "Age": 18,
  "Name": "jinzhu_2", "Age": 20,
)

注意: 根据 map 创建记录时,association 不会被调用,且主键也不会自动填充

2. 查询

(1) 检索单个对象

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件。若没有找到记录时,它会返回 ErrRecordNotFound 错误

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;

// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;

// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error

// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)

FirstLast 方法会根据主键查找到第一个、最后一个记录, 它仅在通过 struct 或提供 model 值进行查询时才起作用。 如果 model 类型没有定义主键,则按第一个字段排序。

var user User

// 可以
db.First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1

// 可以
result := map[string]interface
db.Model(&User).First(&result)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1

// 不行
result := map[string]interface
db.Table("users").First(&result)

// 但可以配合 Take 使用
result := map[string]interface
db.Table("users").Take(&result)

// 根据第一个字段排序
type Language struct 
  Code string
  Name string

db.First(&Language)
// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1

(2) 根据主键检索

db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

db.Find(&users, []int1,2,3)
// SELECT * FROM users WHERE id IN (1,2,3);

(3) 检索全部对象

// 获取全部记录
result := db.Find(&users)
// SELECT * FROM users;

result.RowsAffected // 返回找到的记录数,相当于 `len(users)`
result.Error        // returns error

(4) 条件

string条件

// 获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

// 获取全部匹配的记录
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';

// IN
db.Where("name IN ?", []string"jinzhu", "jinzhu 2").Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');

// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';

// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;

// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';

// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

struct或map条件

// Struct
db.Where(&UserName: "jinzhu", Age: 20).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;

// Map
db.Where(map[string]interface"name": "jinzhu", "age": 20).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;

// 主键切片条件
db.Where([]int6420, 21, 22).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);

**注意:**当使用结构体作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为0''false 或其他零值,该字段不会被用于构建查询条件。

(5) 内联条件

// SELECT * FROM users WHERE id = 23;
// 根据主键获取记录,如果是非整型主键
db.First(&user, "id = ?", "string_primary_key")
// SELECT * FROM users WHERE id = 'string_primary_key';

// Plain SQL
db.Find(&user, "name = ?", "jinzhu")
// SELECT * FROM users WHERE name = "jinzhu";

db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;

// Struct
db.Find(&users, UserAge: 20)
// SELECT * FROM users WHERE age = 20;

// Map
db.Find(&users, map[string]interface"age": 20)
// SELECT * FROM users WHERE age = 20;

(6) not条件

db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;

// Not In
db.Not(map[string]interface"name": []string"jinzhu", "jinzhu 2").Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

// Struct
db.Not(UserName: "jinzhu", Age: 18).First(&user)
// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;

// 不在主键切片中的记录
db.Not([]int641,2,3).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;

(7) or条件

db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct
db.Where("name = 'jinzhu'").Or(UserName: "jinzhu 2", Age: 18).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

// Map
db.Where("name = 'jinzhu'").Or(map[string]interface"name": "jinzhu 2", "age": 18).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

(8) 选择特定字段

db.Select("name", "age").Find(&users)
// SELECT name, age FROM users;

db.Select([]string"name", "age").Find(&users)
// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users;

(9) 排序

db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

// 多个 order
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

db.Clauses(clause.OrderBy
  Expression: clause.ExprSQL: "FIELD(id,?)", Vars: []interface[]int1, 2, 3, WithoutParentheses: true,
).Find(&User)
// SELECT * FROM users ORDER BY FIELD(id,1,2,3)

(10) limit & offset

Limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量

db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;

// 通过 -1 消除 Limit 条件
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)

db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;

db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;

// 通过 -1 消除 Offset 条件
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)

(11) group & having

db.Model(&User).Select("name, sum(age) as total").Group("name").golang goroutine例子[golang并发代码片段]

Golang学习笔记

学习笔记Golang语法学习笔记

golang学习笔记6——并发

golang学习笔记2——容器和流程控制

go学习Golang底层学习笔记