zoukankan      html  css  js  c++  java
  • Go语言gorm框架MySQL实践

    gorm是一个使用Go语言编写的ORM框架。文档齐全,对开发者友好,支持主流数据库。

    我最近在补齐Go语言各类基础的框架和操作库的知识,终于进展到了数据库阶段,搜资料的时候基本都是推荐这个框架,可见其之流行程度。在不断尝试练习之后,总结了一些经验和使用方式,供初学者参考。

    在之前使用Java语言的时候用过两种JDBC和mybatis,一种是本地操作数据库的一种是在Springboot项目中使用,两者使用习惯上都是基于MySQL语句,都是在操作层面把MySQL语句拼写完成。但是在gorm框架中几乎看不到完整的SQL语句,都是通过方法和参数

    go.mod

    github.com/jinzhu/gorm v1.9.16

    在执行Go Mod Tidy的时候会把相关需要的依赖(这个用词可能不准)自动添加到mod文件中。

    go.mod我现在也不是很熟悉,我也是抄能力发动+IDE提示完成的,通常来说比较顺利。

    我的代码中依赖如下:

    import (
    	"fmt"
    	"funtester/base"
    	"funtester/futil"
    	"github.com/jinzhu/gorm"
    	_ "github.com/jinzhu/gorm/dialects/mysql"
    	"log"
    	"testing"
    	"time"
    )
    

    初始化

    这个演示Demo,内容偏基础,高阶的我也不会用,目前也用不到。演示分两类:初始化连接,初始化数据库。由于gorm自带了数据库初始化功能,会将Model对应数据库表创建(这个需要手动开启),所以这个在测试中还是比较常用的,如果辅以数据初始化的方法,基本满足我们日常开发测试服务的需求。

    func init() {
    	var err error
    	drive, err = gorm.Open("mysql", "root:root123456@(localhost:3306)/funtester?charset=utf8&parseTime=true")
    	if err != nil {
    		fmt.Println(err)
    		log.Fatalln("mysql conntect err")
    	}
    	drive.DB().SetMaxOpenConns(200)
    	drive.DB().SetConnMaxLifetime(10 * time.Second)
    	drive.DB().SetConnMaxIdleTime(10 * time.Second)
    	drive.DB().SetMaxIdleConns(20)
    	// 迁移 schema
    	drive.AutoMigrate(&Funtester{})
    	//注意: AutoMigrate 会创建表,缺少的外键,约束,列和索引,并且会更改现有列的类型(如果其大小、精度、是否为空可更改)。但 不会 删除未使用的列,以保护您的数据。
    	//db.AutoMigrate(&User{}, &Product{}, &Order{})
    	//drive.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&Funtester{})//带参数的迁移
    
    }
    
    

    Model

    type Funtester struct {
    	gorm.Model
    	Name string
    	Age  int
    }
    

    这里分享一下MySQL数据库表结构:

    DROP TABLE IF EXISTS `funtesters`;
    CREATE TABLE `funtesters` (
      `id` int unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(255) DEFAULT NULL,
      `age` int unsigned DEFAULT NULL,
      `created_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `created_at` datetime DEFAULT NULL,
      `updated_at` datetime DEFAULT NULL,
      `deleted_at` datetime DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_funtesters_deleted_at` (`deleted_at`)
    ) ENGINE=InnoDB AUTO_INCREMENT=241861 DEFAULT CHARSET=utf8mb3;
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    

    这里应该就比较清晰看到gorm初始化数据库的时候的逻辑了。这里分享一下gorm.Model源码:

    type Model struct {
    	ID        uint `gorm:"primary_key"`
    	CreatedAt time.Time
    	UpdatedAt time.Time
    	DeletedAt *time.Time `sql:"index"`
    }
    
    

    select

    下面演示一下select常用语法,这里分成了两个:一个偏基础,一个偏复杂(主要是多查询条件串联)。这里可以很明显看出gorm拼接查询条件的思路,就是把查询条件分类然后单独写不同的条件,由gorm框架做SQL语句的拼接。

    func TestSelect1(t *testing.T) {
    	var f Funtester
    	drive.First(&f, 34)//默认id
    	last := drive.Last(&f, "age != 1")//添加条件
    	fmt.Printf("查询到记录数 %d "+base.LINE, last.RowsAffected)
    	fmt.Println(f)
    	take := drive.Take(&f) //不指定顺序
    	fmt.Println(take.RowsAffected)
    }
    // TestSelect2
    // @Description: 常用查询和处理结果
    // @param t
    func TestSelect2(t *testing.T) {
    	var fs []Funtester
    	var f Funtester
    	drive.Where("id = ?", 45).First(&f)//另外一种写法
    	//fmt.Println(f)
    	find := drive.Where("name like ?", "fun%").Find(&fs).Limit(10).Order("id")//多查询条件串联
    	rows, _ := find.Rows()//获取结果
    	defer rows.Close()
    	for rows.Next() {
    		var ff Funtester
    		drive.ScanRows(rows, &ff)
    		fmt.Println(ff.Age, ff.Name)
    	}
    	//另外一种写法
    	var f1 Funtester
    	drive.Where("name LIKE ?", "fun").Or("id = ?", 123).First(&f1)
    	fmt.Println(f1)
    
    }
    
    

    update

    有了select的基础,再来看update就比较容易了。

    // TestUpdate
    // @Description: 更新
    // @param t
    func TestUpdate(t *testing.T) {
    	drive.Model(&Funtester{}).Where("id = ?", 241860).Update("name", base.FunTester+"3")
    }
    

    insert

    gorm官文文档支持批量插入的,但是这个依赖包中并没有相关支持。各位如果使用跟我一样的依赖的话,

    // TestInsert
    // @Description: 增加
    // @param t
    func TestInsert(t *testing.T) {
    	value := &Funtester{Name: "FunTester" + futil.RandomStr(10)}
    	drive.Create(value)
    	drive.Select("name", "age").Create(value) //只创建name和age字段的值
    	futil.Sleep(1)
    	drive.Omit("age", "name").Create(&Funtester{Name: "fds",Age: 122})   //过滤age和name字段创建
    	fs := []Funtester{{Name: "fs" + futil.RandomStr(10), Age: 12}, {Name: "fs" + futil.RandomStr(10), Age: 12}}
    	drive.Create(&fs)//这里不支持这么操作的
    }
    

    delete

    删除操作跟以上两种操作使用方式一致。

    func TestDelete(t *testing.T) {
    	db := drive.Where("id = ?", 241859).Delete(&Funtester{})
    	fmt.Println(db.RowsAffected)
    }
    

    执行SQL

    当然gorm也是支持直接执行SQL语句的,有一个特殊就是执行查询语句的时候需要解析查询结果。

    // TestSql
    // @Description: 直接执行SQL
    // @param t
    func TestSql(t *testing.T) {
    	var funtester []Funtester
    	scan := drive.Raw("select * from funtesters where id > 333 limit 10").Scan(&funtester)
    	fmt.Println(scan.RowsAffected)
    	fmt.Println(funtester)
    }
    

    事务&回滚

    在gorm高级语法的使用中,我觉得这个是非常实用的,对于一些测试语句的执行非常适合。

    // TestRollBack
    // @Description: 事务&回滚
    // @param t
    func TestRollBack(t *testing.T) {
    	funtester := Funtester{Name: base.FunTester, Age: 32232}
    	begin := drive.Begin()
    	err := begin.Create(&funtester).Error
    	if err != nil {
    		begin.Rollback()
    	}
    	begin.Commit()
    
    }
    
    

    gorm的基本使用已经分享完了,下次分享使用gorm做性能测试的实践。

    Have Fun ~ Tester !

  • 相关阅读:
    Docker的安装、配置及其基本使用
    Java提升七:注解
    Java提升六:泛型
    Java提升五:反射与动态代理
    MySQL中如何将主键默认值设为UUID()
    图解Mybatis框架原理及使用
    Java提升四:Stream流
    Java提升三:函数式接口
    Java提升二:Lambda表达式与方法引用
    java提升一:内部类
  • 原文地址:https://www.cnblogs.com/FunTester/p/15789699.html
Copyright © 2011-2022 走看看