美文网首页
区块链Two——数据库(3)—Gorm

区块链Two——数据库(3)—Gorm

作者: 秃头小公主 | 来源:发表于2020-11-11 11:34 被阅读0次

     这应该是学习的第四天了,简单来说一下博客的顺序,也就是我学习的顺序:go语言->区块链(因为实习就知道会用到这个技术就直接学了,其实可以再这之前接触一下以太坊)->Gorm(在学习区块链的时候,用到数据库了所以学习了一下gorm相关知识,因为java有过ORM的基础所以个人认为还是比较好理解的)->区块链(又回到区块链,继续学习,其实在这之前简单学习了一下Rabbimq)

    整体来说我的学习路程感觉杂乱无章,我也不知道对不对。明天可能就会简单看一下项目代码,那具体有什么情况可能再去学习的话再来写一写文章。


    CRUD:增删改查

    1.创建

    (1)创建记录

    user := User{Name:"Jinzhu", Age:18, Birthday: time.Now()}

    db.NewRecord(user) //主键为空返回true

    db.Create(&user)db.NewRecord(user) //创建user后返回false

    (2)默认值(在gorm tag中定义)

    插入SQL会忽略有默认值的字段,并且其值为空。记录插入数据库之后,gorm从数据库加载这些字段的值

    type Animal struct{

          ID  int64

          Name  string  `gorm:"default:'默认值'"` //设置默认值

          Age  int64

    }

    上述会将所有的0值字段全部赋成默认值,如果你想避免这种情况可以使用指针或者Scanner/Valuer接口,例如:

    <1>使用指针:

    type User struct {  

         ID   int64

         Name *string `gorm:"default:'默认值'"`

         Age  int64

    }

    user := User{Name: new(string), Age: 18))}

    db.Create(&user)  //此时数据库中该条记录name字段的值就是‘ ’

    <2>使用 Scanner/Valuer:

    type User struct {  // 使用 Scanner/Valuer

           ID int64

           Name sql.NullString `gorm:"default:'默认值'"` // sql.NullString 实现了Scanner/Valuer接口

           Age  int64

    }

    user := User{Name: sql.NullString{"", true}, Age:18}

    db.Create(&user) // 此时数据库中该条记录name字段的值就是‘ ’

    (3)在Callbacks(回调函数)中设置主键

    func (user *User) BeforeCreate (scope *gorm.Scope) error{

                scope.SetColumn("ID", uuid.New()) //设置主键

                return  nil

    }

    (4)扩展创建选项(有则更新,无则插入)

     db.Set("gorm:insert_option","ON CONFLICT").Create(&product)

    2.查询

    (1)基本查询

    db.First(&user) //获取第一条记录,按主键排序

    db.Last(&user) //获取最后一条记录,按主键排序

    db.Find(&users) //获取所有记录

    db.First(&user,10) //使用主键获取记录,id=10

    (2)Where查询条件

              <1>简单SQL

                    db.Where("name = ?","memgyu").First(&user) //查询第一个匹配的数据

                    db.Where("name = ?","mengyu").Find(&users) //查询所有匹配的数据

                    db.Where("name <> ?","mengyu").Find(&users) //查询name不是mengyu的数据

                    db.Where("name in (?)", []string{"mengyu1","mengyu 2"}).Find(&users) //查询出name在(mengyu1,mengyu2)所有数据

                    db.Where("name LIKE ?","%jin%").Find(&users) //模糊查询

                    db.Where("name = ? AND age >= ?","mengyu","22").Find(&users) //查询name=mengyu并且age>=22的数据

                    db.Where("updated_at > ?", lastWeek).Find(&users) //查询上一周的数据

                    db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users) //查询上一周到今天的数据

                <2>Struct & Map(Struct查询只查询有值的字段)

                    db.Where(&User{Name:"mengyu", Age:20}).First(&user)  //Struct:查询name=mengyu,age=20,从第一条数据开始查

                    db.Where(map[string]interface{}{"name":"mengyu","age":20}).Find(&users) //Map:查询name=mengyu,age=20的数据

                    db.Where([]int64{20,21,22}).Find(&users) //多主键slice查询:查询id=20,21,22的数据(数据量小的时候查询速度比map快)

    (3)Not条件查询  

    db.Not("name","mengyu").First(&user) //查询name≠mengyu的第一条数据

    db.Not("name", []string{"mengyu1","mengyu2"}).Find(&users) //查询name≠memgyu1和mengyu2的数据

    db.Not([]int64{1,2,3}).First(&user) //查询id为1、2、3的数据

    db.Not([]int64{}).First(&user) //查询所有数据

    db.Not("name = ?","mengyu").First(&user) //查询name≠mengyu的数据

    db.Not(User{Name:"mengyu"}).First(&user) //查询name≠mengyu的数据

    (4)带内联条件的查询

    db.First(&user,23) //查询id=23的第一条数据

    db.Find(&user,"name = ?","mengyu") //查询name=mengyu的数据

    db.Find(&users,"name <> ? AND age > ?","mengyu",20) //查询name≠mengyu并且age=20的数据

    db.Find(&users, User{Age:20}) //struct查询:查询age=20的数据

    db.Find(&users,map[string]interface{}{"age":20}) //Map查询:查询age=20的数据

    (5)Or条件查询

    db.Where("role = ?","admin").Or("role = ?","super_admin").Find(&users) //查询角色为admin或者super_admin的角色

    db.Where("name = 'mengyu1'").Or(User{Name:"mengyu2"}).Find(&users) ///struct查询:查询name=mengyu1或mengyu2的数据

    db.Where("name = 'mengyu1'").Or(map[string]interface{}{"name":"mengyu 2"}).Find(&users) //Map查询:查询name=mengyu1或mengyu2的数据

    (6)查询链(使用gorm自带的api)

    db.Where("条件","条件的值").Where/Or/Not(...).Find(&表名)

    (7)扩展查询选项

    db.Set("gorm:query_option","FOR UPDATE").First(&user,10) // 若id=10有数据,则row lock(行锁)

    (8)FirstOrInit(只适用Struct和Map)

    db.FirstOrInit(&user, User{Name: "non_existing"}) //没查询到匹配的数据则初始化

    db.FirstOrInit(&user,map[string]interface{}{"name":"mengyu"}) //获取匹配到的第一条数据

    (9)Attrs

    db.Where(User{Name:"mengyu"}).Attrs(User{Age:18}).FirstOrInit(&user)//没找到数据则初始化,找到则显示

    (10)Assign

    db.Where(User{Name:"mengyu"}).Assign(User{Age:20}).FirstOrInit(&user) //将age=20分配给name=mengyu的数据(不论找没找到)

    (11)FirstOrCreate(只适用Struct和Map)

    db.FirstOrCreate(&user, User{Name:"mengyu"}) //没有获取到,则创建新信息

    db.Where(User{Name:"mengyu"}).FirstOrCreate(&user) //找到了则获取第一条name=mengyu的数据

    (12)Select

    db.Table("users").Select("COALESCE(age,?)",42).Rows() //返回第一个age=42并且非空的值

    (13)Order

    db.Order("age desc").Order("name").Find(&users) //按照年龄降序(asc为升序;desc为降序)查询数据的age和name

    (14)Limit

    db.Limit(10).Find(&users1).Limit(-1).Find(&users2) //查询user1的前10条数据;查询user2所有数据(Limit(-1)用来取消之前的限制条件)

    (15)Offset

    db.Offset(10).Find(&users1).Offset(-1).Find(&users2) ///查询user1的跳过前10条数据;查询user2所有数据(Offset(-1)用来取消之前的限制条件)

    (16)Count

    db.Model(&User{}).Where("name = ?","mengyu").Count(&count) //查询name=mengyu的数据有多少条

    (17)还有一部分关键字,我没怎么太接触,打算以后遇到了再仔细研究。想看的小伙伴可以看原版

    (17)指定表名

    db.Table("users1").CreateTable(&User{}) //使用user结构体定义创建users1表

    var users1 []User //来一个user1

    db.Table("users1").Where("name = ?","mengyu").Delete() //查询name=mengyu的数据

    3.预加载

    (1)预加载

    预加载是指暂时下载,是储存在你电脑的隐藏文件夹里的,当它的储存量超过一定数值时,会抵消最开始的缓存

    db.Preload("Orders","state NOT IN (?)","cancelled").Find(&users) //从表Orders找到id=1,2,3,4并且列(state)≠cancelled进行预加载

    (2)自定义预加载SQL

    可以通过传递func(db *gorm.DB) *gorm.DB来自定义预加载SQL

    db.Preload("Orders",func(db *gorm.DB)*gorm.DB{returndb.Order("orders.amount DESC")}).Find(&users) //从表Orders查询user_id=1,2,3,4并且降序排列进行预加载

    (3)嵌套加载

    db.Preload("Orders.OrderItems").Find(&users)

    db.Preload("Orders","state = ?","paid").Preload("Orders.OrderItems").Find(&users)

    4.更新

    (1)更新全部字段
    db.First(&user) //获取第一条信息

    user.Name ="mengyu"  //更新name=mengyu

    user.Age =100 //更新age=100

    db.Save(&user) //更新全部字段,即使有些字段没有更改

    (2)更新更改字段

    db.Model(&user).Update("name","hello") //更新name=hello(单个属性)

    db.Model(&user).Where("active = ?",true).Update("name","hello") //使用组合条件更新单个属性

    db.Model(&user).Updates(map[string]interface{}{"name":"hello","age":18,"actived":false}) //使用`map`更新多个属性,只会更新这些更改的字段

    db.Model(&user).Updates(User{Name:"hello", Age:18}) //使用`struct`更新多个属性,只会更新这些更改的和非空白字段

    db.Model(&user).Updates(User{Name:"", Age:0, Actived:false}) //struct是不会更新 “ ”、0、false的,因为他们属于类型的空白值。struct不会更新空白值

    (3)更新选择的字段

    db.Model(&user).Select("name").Updates(map[string]interface{}{"name":"hello","age":18,"actived":false}) //也可以将Select改为Omit,再更新时更新或者忽略

    (4)更新更改字段但不进行Callbacks

    前面所说的更新操作会执行模型的BeforeUpdate, AfterUpdate方法,更新其UpdatedAt时间戳,在更新时保存它的Associations,如果不想调用它们,可以使用UpdateColumn, UpdateColumns

    db.Model(&user).UpdateColumn("name","hello") //更新单/多个属性时与update类似

    (5)Batch Updates 批量更新

    Callbacks(回调函数在最后面做了笔记)在批量更新时不会运行

    db.Table("users").Where("id IN (?)", []int{10,11}).Updates(map[string]interface{}{"name":"hello","age":18}) //就正常更新

    db.Model(User{}).Updates(User{Name:"hello", Age:18}) //Struct更新:适用非零值,也可以用map[string]interface{}

    db.Model(User{}).Updates(User{Name:"hello", Age:18}).RowsAffected //RowsAffected获取更新条数

    (6)在Callbacks中更改更新值

    如果要使用BeforeUpdate, BeforeSave更改回调中的更新值,可以使用scope.SetColumn,例如

    func(user *User)BeforeSave(scope *gorm.Scope)(err error){

        if  pw, err := bcrypt.GenerateFromPassword(user.Password,0); err ==nil{

            scope.SetColumn("EncryptedPassword", pw)

        }

    }

    (7)额外更新选项

    db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello") //添加额外的SQL

    5.删除/软删除

    (1)单个删除

    删除记录时,需要确保其主要字段有值,GORM将使用主键删除记录,如果主要字段为空,GORM将删除模型的所有记录

    db.Delete(&email) //删除存在的记录

    (2)批量产出

    db.Where("email LIKE ?","%mengyu%").Delete(Email{}) //删除所有email=mengyu的数据

    db.Delete(Email{},"email LIKE ?","%jinzhu%") //也可以这么表达

    (3)软删除

    如果模型有DeletedAt字段,它将自动获得软删除功能。在调用Delete时不会从数据库中永久删除,只将字段DeletedAt的值设置为当前时间。

    db.Where("age = ?",20).Delete(&User{}) //软删除了所有age=20的数据

    db.Where("age = 20").Find(&user) //查询软删除(查询结果为null),软删除的数据查询时候被忽略

    db.Unscoped().Where("age = 20").Find(&users) // Unscoped查找软删除记录

    db.Unscoped().Delete(&order) //Unscoped永久删除

    6.关联

    默认情况下,当创建/更新记录时,GORM将保存其关联,如果关联具有主键,GORM将调用Update来保存它,否则将被创建。

    (1)tag设置跳过保存关联

    type User struct{ 

        gorm.Model

        Name  string

        CompanyID  uint

        Company  Company  `gorm:"save_associations:false"` //跳过保存关联

    }

    type Company struct{ 

          gorm.Model

          Name  string

    }

    7.Callbacks

    回调方法:模型结构的指针,在创建,更新,查询,删除时将被调用,如果任何回调返回错误,gorm将停止未来操作并回滚所有更改。

    (1)创建对象过程中可用的回调

    // begin transaction 

    开始事物BeforeSaveBeforeCreate

    //save before associations 保存前关联

    //update timestamp `CreatedAt`, `UpdatedAt` 更新`CreatedAt`, `UpdatedAt`时间戳

    //save self 保存自己

    //reload fields that have default value and its value is blank 重新加载具有默认值且其值为空的字段

    //save after associations 保存后关联

    AfterCreate

    AfterSave

    //commit or rollback transaction 提交或回滚事务

    (2)更新对象过程中可用的回调

    //begin transaction 

    开始事物BeforeSaveBeforeUpdate

    //save before associations 保存前关联

    //update timestamp `UpdatedAt` 更新`UpdatedAt`时间戳

    //save self 保存自己

    //save after associations 保存后关联

    AfterUpdate

    AfterSave

    //commit or rollback transaction 提交或回滚事务

    (3)删除对象过程中可用的回调

    //begin transaction 

    开始事物BeforeDelete

    //delete self 删除自己

    AfterDelete

    //commit or rollback transaction 提交或回滚事务

    (4)查询对象过程中可用的回调

    //load data from database 从数据库加载数据

    //Preloading (edger loading) 预加载(加载)

    AfterFind

    (5)举个栗子~

    func (u *User) BeforeUpdate() (err error){

           if u.readonly() { 

                err = errors.New("read only user")

           }

          return

    }

    func (u *User) AfterCreate() (err error) { //如果用户ID大于1000,则回滚插入

           if(u.Id >1000) {  

                  err = errors.New("user id is already greater than 1000") 

            }

           return

    }

    gorm中的保存/删除操作正在事务中运行,因此在该事务中所做的更改不可见,除非提交。 如果要在回调中使用这些更改,则需要在同一事务中运行SQL。 所以你需要传递当前事务到回调,像这样:

    func (u *User) AfterCreate (tx *gorm.DB) (err error) {

          tx.Model(u).Update("role","admin")

          return

    }

    func (u *User) AfterCreate (scope *gorm.Scope) (err error) {

           scope.DB().Model(u).Update("role","admin")

           return

    }

    相关文章

      网友评论

          本文标题:区块链Two——数据库(3)—Gorm

          本文链接:https://www.haomeiwen.com/subject/xbjrbktx.html