开发者

Go ORM的封装解决方式详解

开发者 https://www.devze.com 2023-01-14 10:52 出处:网络 作者: Afu
目录背景Java的ormGo的orm解决方式初始化sql连接数据库插入语句查询语句gplus工具最后背景
目录
  • 背景
  • Java的orm
  • Go的orm
  • 解决方式
    • 初始化sql
    • 连接数据库
    • 插入语句
    • 查询语句
  • gplus工具
    • 最后

      背景

      去年慢慢开始接触了Go语言,也在公司写了几个Go的生产项目。我是从Java转过来的。(其实也不算转,公司用啥,我用啥)在这个过程中,老是想用Java的思维写Go,在开始的一两个月,那是边写边吐槽。

      丑陋的错误处理,没有流式处理,还竟然没有泛型,框架生态链不成熟,没有一家独大的类似Spring的框架。(其实现在写了快一年的Go,Go还是挺香的,哈哈)

      今天,我来聊一下,我在我在写Go过程中用的最多orm框架gorm。

      Java的orm

      写过Java的基本都知道MyBATis,Mybatis-plus。

      在Mybatis-plus中操作单表非常方便,通过QueryWrappe开发者_C入门r,对于单表的操作非常的丝滑,没有任何http://www.devze.com的思维负担。

      类似下面这样:

              QueryWrapper<User> queryWrapper = new QueryWrapper<>();
              queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
              userMapper.selectList(queryWrapper);
      

      Go的orm

      这里的条件查询都需要开发手动来拼接字符串,如果项目比较大的话,就会看到漫天飞的SQL字段,维护起来非常麻烦。

        var users []*User
        sqlResult := db.Where("username = ? and age = ?", "zhangsan", 18).Find(&users)
      

      解决方式

      写了一段时间的Go之后,实在不想每次都写这些字符串拼接了,于是我给gorm封装了一个gorm-plus。

      这里我使用到了go 1.18的泛型。泛型出了这么久,也该使用上了。

      其实就是把Mybatis-plus的那套语法借鉴了一下。(好吧,就是抄他的)

      Mybatis-plus对于单表操作提供了非常多的CRUD操作。

      Go ORM的封装解决方式详解

      我给gorm-plus 也提供了类似的操作

      Go ORM的封装解决方式详解

      下面是具体用法

      下载:

      go get github.com/acmestack/gorm-plus
      

      初始化sql

      DROP TABLE IF EXISTS `users`;
      CREATE TABLE `users`  (
                                `id` int(0) NOT NULL AUTO_INCREMENT,
                                `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                                `password` varchar(255) CHARACTER androidSET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                                `age` int(0) NULL DEFAULT NULL,
                                `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                                `score` int(0) NULL DEFAULT NULL,
                                `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                                `dept` varchar(255) CHARACTER SET utf8mb编程4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                                `created_at` datetime(0) NULL DEFAULT NULL,
                                `updated_at` datetime(0) NULL DEFAULT NULL,
                                PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
      SET FOREIGN_KEY_CHECKS = 1;
      

      连接数据库

      var GormDb *gorm.DB
      func init() {
        dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
        var err error
        GormDb, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
          Logger: logger.Default.LogMode(logger.Info),
        })
        if err != nil {
          log.Fatalln(err)
        }
        gplus.Init(GormDb)
      }
      

      插入语句

        user := &User{Username: "zhangsan", Password: "123456", Age: 18, Score: 100, Dept: "A部门"}
        result := gplus.Insert(user)
        fmt.Println(result.RowsAffected)
      

      查询语句

      根据id查询:

      注意这里需要传入泛型User

        user, resultDb := gplus.SelectById[User](1)
        fmt.Println(user, resultDb.RowsAffected)
      

      根据ids查询:

        var ids = []int{1,2}
        users, resultDb := gplus.SelectByIds[User](ids)
        fmt.Println(users, resultDb.RowsAffected)
      

      条件查询:

        q := gplus.NewQuery[User]()
        q.Eq("username", "zhangsan").Eq("age",18)
        users, resultDb := gplus.SelectList(q)
        fmt.Println(users,resultDb.RowsAffected)
      

      对比一下Mybatis-plus写法基本一致了。

              QueryWrapper<User> queryWrapper = new QueryWrapper<>();
              queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
              userMapper.selectList(queryWrapper);
      

      更多操作请查看:

      github.com/acmestack/g…

      gplus工具

      其实上面的写法还是需要写数据库的字段名,如果数据库的字段名很多,我们很容易写错,导致不必要的bug 产生。

      一旦名称长,非常容易误写,而且如果有字段名称修改的话,还需要全局搜索一个个地修改,比较麻烦。

      Go没有提供类似Java的lambad表达式或者C#中 nameof 方式直接获取某个对象的字段名称的操作,但是我们可以www.devze.com通过生成代码的方式生成字段名。

      所有就有了gplus,它作用就是自动识别结构体,把结构体的字段名生成出来。

      下载使用:

      go install github.com/acmestack/gorm-plus/cmd/gplus@latest
      

      通过 gplus gen paths=路径,gplus 会自动识别带有// +gplus:column=true注释的结构体,给这个结构体生成字段。

      gplus 会在输入的路径下面生成 zz_gen.column.go文件。

      例如:

      在example目录下创建了了一个users.go 目录,执行 gplus gen paths=./eample

      users.go

      // +gplus:column=true
      type User struct {
        ID        int64
        Username  string `gorm:"column:username"`
        Password  string
        Address   string
        Age       int
        Phone     string
        Score     javascriptint
        Dept      string
        CreatedAt time.Time
        UpdatedAt time.Time
      }
      

      zz_gen.column.go (自动生成的)

      var UserColumn = struct {
        ID        string
        Username  string
        Password  string
        Address   string
        Age       string
        Phone     string
        Score     string
        Dept      string
        CreatedAt string
        UpdatedAt string
      }{
        ID:        "id",
        Username:  "username",
        Password:  "password",
        Address:   "address",
        Age:       "age",
        Phone:     "phone",
        Score:     "score",
        Dept:      "dept",
        CreatedAt: "created_at",
        UpdatedAt: "updated_at",
      }
      

      其实你自己也可以手写这个文件,只不过通过工具生成更加方便而已。

      有了这个文件,我们的查询就变成这样:

        q := gplus.NewQuery[User]()
        q.Eq(UserColumn.Username, "zhangsan").Eq(UserColumn.Age,18)
        users, resultDb := gplus.SelectList(q)
        fmt.Println(users,resultDb.RowsAffected)
      

      这样维护起来就非常方便了。

      最后

      更多的用法请查看github地址:https://github.com/acmestack/gorm-plus

      以上就是Go ORM的封装解决方式详解的详细内容,更多关于Go ORM封装的资料请关注我们其它相关文章!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号