golang数据库编程(gorm版)(一)

用golang操作数据库的方法很多。golang自带databse/sql包,直接引用包里面的方法就可以操作数据库。使用beego框架时,beego也自带了一套orm模型。而gorm则是基于database/sql封装了一套完备的数据库操作方法。

进行数据库编程,至少要了解数据库的基础知识。比如表、字段、字段类型的定义,增删改查的动作。本文不再赘述这些基础知识,有需要了解的自行搜索了解。

与数据库交互,第一步动作即是建立与数据库的连接。以mysql为例:

dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?allowNativePasswords=true&charset=utf8mb4&parseTime=true&loc=Local", dbUser, dbPwd, dbAddr, dbPort, dbName)
	fmt.Println("数据库链接:", dbAddr)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("初始化数据库连接错误:", err.Error())
		return
	} else {
		fmt.Println("初始化数据库连接成功!")
	}

连接建立成功后,变量db就是gorm提供的数据库连接对象,我们不必关注其内部是如何连接数据库的,实际上在gorm内部是有一个连接池,db对象在操作数据的时候,会从连接池中选择一个空闲的连接与数据库进行交互。

如同我们去4S店给车做保养一样,我们得先把车开到4S店,将车交给前台的售后人员(db),他来负责将车开到保养工房,再安排一个维修工程师给我们的汽车做保养。排在我们后面的客人再来找这位售人员(db),如果还有空闲的维修保养工程师,则立即安排对后面客人的车进行保养。诸如此类,直到所有的维修保养工程师都在工作了,后面再来客人,就需要等待前面的车完成维保把位置空出来,或者后面的客人离开该4S店,另寻他处进行维保。至于售后人员(db)具体找的是哪位维保人员给我们车做维保,事实上我们根本无需关心。

在这里,我们要注意的是db是一个gorm对象,而gorm完成了对dababase/sql的封装,真正操作数据,实际上是在sql.DB中完成的。如果要对数据库的连接进行一些设置,需要在sql.DB中完成,无法直接用db对象来操作,比如设置连接的空闲最大时长,空闲最大连接数等。

SqlDB, err = db.DB()
	if err != nil {
		fmt.Println("获取数据库连接出错:", err.Error())
		return
	}

	SqlDB.SetConnMaxIdleTime(time.Hour * time.Duration(attr.DbMaxOpenConns))
	SqlDB.SetMaxIdleConns(int(attr.DbMaxIdleConns))

gorm为我们做了一些额外的封装,简化了我们的很多动作。比如当我们定义或者修改数据模型后,对应的数据库的表结构也需要调整,才能与数据模型保持一致。gorm提供了AutoMigrate方法,该方法的功能是将数据模型同步到数据库对应的表结构中,模型中的字段类型如果被改动,或者新增了字段,对应的表结构也会相应的调整。如果数据库中还没有该表,则直接按模型描述创建新表。(描述模型后面再细说)

//自动根据结构体创建表结构
	e := db.AutoMigrate(		
		&Order{},                   //订单表		
		&RequestInfo{},             //请求信息表
		&Mobile{},                  //手机号表
	)

gorm是如何知道我们要操作的表的表名呢?总不可能我们全部手写sql吧。这个不用担心,在gorm中,每个模型有一个TableName的方法,该方法让gorm知道我们要操作的数据库表具体是哪一张。

func (self *Order) TableName() string {
	return "t_order"
}

这里分享一个小技巧,我们建表的时候,通常会根据某些原则设置前缀,这在编写TableName方法的时候,也可以这样来做。比我们希望我们所有表的表名都是"t_“开头,其中订单表的表名为"t_order",则可以如下操作。其中公共的TableName方法放在公共文件中,Order的TableName方法在存放在自己文件中。

func TableName(tableName string) string {
	return "t_" + tableName
}

func (self *Order) TableName() string {
	return TableName("order")
}

用gorm方法对表数据进行增、删、改、查的操作非常方便。

//添加一条记录
func (self *Order) Insert() (int64, error) {
	self.CreateTime = time.Now()
	self.UpdateTime = time.Now()
	tx := db.Create(self)
	return tx.RowsAffected, tx.Error
}

//按条件查询记录
func (self *Order) Select(cols ...string) ([]Order, error) {
	data := make([]Order, 0)
	strQuery := " 1=1 "
	fields := make([]interface{}, 0)
	for _, col := range cols {
		switch col {
		case "id":
			strQuery += " AND id = ?"
			fields = append(fields, self.Id)
		case "tracer_id":
			strQuery += " AND tracer_id = ?"
			fields = append(fields, self.TraceId)
		case "channel":
			strQuery += " AND channel = ?"
			fields = append(fields, self.Channel)
		case "gds_type":
			strQuery += " AND gds_type = ?"
			fields = append(fields, self.GdsType)
		case "tc_order_id":
			strQuery += " AND tc_order_id = ?"
			fields = append(fields, self.TcOrderId)
		case "unit_key":
			strQuery += " AND unit_key = ?"
			fields = append(fields, self.UnitKey)
		case "airline_code":
			strQuery += " AND airline_code = ?"
			fields = append(fields, self.AirlineCode)
		case "contact_name":
			strQuery += " AND contact_name = ?"
			fields = append(fields, self.ContactName)
		case "contact_phone":
			strQuery += " AND contact_phone = ?"
			fields = append(fields, self.ContactName)
		case "status":
			strQuery += " AND status = ?"
			fields = append(fields, self.Status)
		}
	}
	tx := db.Where(strQuery, fields...).Find(&data)
	return data, tx.Error
}

//按主键id修改指定字段
func (self *Order) Update(cols ...string) (int64, error) {
	tx := db.Model(self).Where("id=?", self.Id)
	if tx.Error != nil {
		return 0, tx.Error
	}
	updateFields := make(map[string]interface{})
	for _, col := range cols {
		switch col {
		case "status":
			updateFields["status"] = self.Status
		case "channel":
			updateFields["channel"] = self.Channel
		case "contact_name":
			updateFields["contact_name"] = self.ContactName
		case "contact_phone":
			updateFields["contact_phone"] = self.ContactPhone
		case "contact_email":
			updateFields["contact_email"] = self.ContactEmail
		case "contact_address":
			updateFields["contact_address"] = self.ContactAddress
		case "remarks":
			updateFields["remarks"] = self.Remarks
		case "async":
			updateFields["async"] = self.Async
		}
	}
	self.UpdateTime = time.Now()
	updateFields["update_time"] = self.UpdateTime
	tx = tx.Updates(updateFields)
	return tx.RowsAffected, tx.Error
}

//根据主键id删除记录
func (self *Order) Delete() (int64, error) {
	tx := db.Delete("id=?", self.Id)
	return tx.RowsAffected, tx.Error
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值