天天看点

golang 之 操作数据库 GORM

目录

ORM

库安装

数据库连接

设置db.DB()属性

模型定义

创建表

插入

删除

查询

修改

事务

ORM

ORM(Object Relation Mapping),对象关系映射,实际上就是对数据库的操作进行封装,对上层开发人员屏蔽数据操作的细节,开发人员看到的就是一个个对象,比如著名的Hibernate

学习与查阅:http://gorm.io/zh_CN/docs/index.html

库安装

go get -u github.com/jinzhu/gorm
           

数据库连接

conf := config.Config().DBCfg
	var err error
	orm, err = gorm.Open(conf.Dtype,
		fmt.Sprintf("%s:%[email protected](%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
			conf.User, conf.Password, conf.Addr, conf.Port, conf.Name))
	if err != nil {
		panic(err)
	}
	orm.LogMode(conf.Debug)
           

设置db.DB()属性

连接了以后可以设置数据库的属性

设置连接池信息

db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
           

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放 空闲时间已经超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

MaxOpenConns 表示最大创建tcp连接数。

MaxIdleConns 表示始终保持的tcp连接数,即使连接都关闭了。

模型定义

以一个article的model为例:

type Article struct {
	ID             uint       `gorm:"primary_key" json:"aid"`
	CreatedAt      time.Time  `json:"-"`
	UpdatedAt      time.Time  `json:"-"`
	DeletedAt      *time.Time `sql:"index" json:"-"`
	UserID         uint       `gorm:"index;not null" json:"-"`
	CategoryItemID uint       `gorm:"index;not null" json:"cid"`
	Title          string     `gorm:"type:varchar(100);not null" json:"title"`
	Content        string     `gorm:"type:text;not null;" json:"content"`
	Cover          string     `gorm:"not null" json:"cover"`
	CreateTime     time.Time  `gorm:"not null" json:"create_time"`
	Views          int        `gorm:"default:0" json:"views"`
	Origin         int        `gorm:"not null" json:"origin"` //是否原创 1原创 0转载
	State          int        `gorm:"default:0" json:"-"`     //0正常发布 2并未发布(草稿箱)
	Likes          int        `gorm:"default:0" json:"likes"`
	Favorite       bool       `gorm:"not null" json:"favorite"`
}
           

`gorm:"primary_key"` 这些 是mysql 里面的约束,用来设置主键,建立索引等等

创建表

func InitRelations() {
	db := persistence.GetOrm()
	// 判断存不存在表, 不存在就新建, 否则就是自动迁移(其他修改)
	if !db.HasTable("users") {
		db.CreateTable(&models.User{}, &models.UserInfo{}, &models.Category{}, &models.CategoryItem{},
			&models.Article{}, models.FriendlyLink{})
	} else {
		db.AutoMigrate(&models.User{}, &models.UserInfo{}, &models.Category{}, &models.CategoryItem{},
			&models.Article{}, models.FriendlyLink{})
	}
	initCategory(db)
	initDefaultUser(db)
}
           

直接通过 

db.CreateTable

 就可以创建表了,非常方便,还可以通过 

db.Set

 设置一些额外的表属性,比如默认的charset

创建 models.User{}意味着创建users表,所以表名字的转换规则就是 User -> users

插入

//插入数据
func (br *BaseRepository) Insert(out Out) error {
	return br.db().Create(out).Error
}
           

先构造已给对象,直接调用 

db.Create()

 就可以插入一条记录了

这里面应该传入的就是构造出的上面的Article的类型

调用处的代码:

if err := as.repo.Insert(article); err != nil {

        return models.Response{Err: common.ErrInternal, Data: nil}

    } else {

        //保存草稿

        if article.State == 2 {

            return models.Response{Err: common.Err{Msg: common.MsgSaveArticleSucc}, Data: nil}

        } else {

            return models.Response{Err: common.Err{Msg: common.MsgCreateArticleSucc}, Data: nil}

        }

    }

           

删除

//删除数据, 单个或者多个
func (br *BaseRepository) Del(where Where, out Out) error {
	return br.db().Scopes(where).Delete(out).Error
}
           

先用 

db.Where()

 构造查询条件,再调用 

db.Delete()

 就可以删除

Scopes可以用来动态添加条件

查询

//查单个
func (br *BaseRepository) Select(where Where, out Out) bool {
	return br.Exec(where, out, 0, 1)
}

//查全部
func (br *BaseRepository) SelectMany(where Where, out Out) bool {
	return br.Exec(where, out, 0, -1)
}
           

使用的时候的例子:

//获取全部用户数据
func (ur *UserRepository) GetAll() ([]models.User, bool) {
    users := make([]models.User, 0)
    return users, ur.SelectMany(func(db *gorm.DB) *gorm.DB {
        return db.Preload("UserInfo")

    }, &users)

}

//根据用户Id获取用户
func (ur *UserRepository) GetByUserId(id int) (*models.User, bool) {
	user := &models.User{}
	found := ur.Select(func(db *gorm.DB) *gorm.DB {
		return db.Where("id = ?", id)
	}, user)
	if found {
		ur.db().Model(user).Related(&user.UserInfo)
	}
	return user, found
}
           

修改

//更新数据 ,单个 或者 多个
func (br *BaseRepository) Update(out Out, params map[string]interface{}) error {
	return br.db().Model(out).Update(params).Error
}
           

修改时候的例子:

//登录成功修改用户登录信息
user.LoginIP = sql.NullString{String: ip, Valid: true}
user.LoginTime = time.Now()

if err := us.repo.Update(user, map[string]interface{}{"login_ip": user.LoginIP,             
    "login_time": user.LoginTime}); err != nil {
	return models.Response{Err: common.ErrInternal, Data: nil}
}
           

错误处理

其实你已经看到了,这里基本上所有的函数都是链式的,全部都返回 

db

 对象,任何时候调用 

db.Error

 就能获取到错误信息,非常方便

事务

func CreateAnimals(db *gorm.DB) err {
    tx := db.Begin()
    if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
        tx.Rollback()
        return err
    }
    if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
        tx.Rollback()
        return err
    }
    tx.Commit()
    return nil
}
           

事务的处理也很简单,用 

db.Begin()

 声明开启事务,结束的时候调用 

tx.Commit()

,异常的时候调用 

tx.Rollback()

其他

还可以使用如下方式设置日志输出级别以及改变日志输出地方

db.LogMode(true)
db.SetLogger(gorm.Logger{revel.TRACE})
db.SetLogger(log.New(os.Stdout, "\r\n", 0))
           

参考文章:https://studygolang.com/articles/12372