Golang处理数据库的nil数据
2018-10-02 23:02
357 查看
在用golang获取数据库的数据的时候,难免会遇到可控field。这个时候拿到的数据如果直接用
string,
time.Time这样的类型来解析的话会遇到panic。
那么如何处理这个问题呢,第一个出现在眼前的办法就是用
database/sql。这个包里包含了很多的可以处理可控字段的类型,比如:
sql.NullString,
sql.NullBool等。所以,model可以用这些类型来定义,如:
package main import ( "database/sql" "fmt" "github.com/go-sql-driver/mysql" ) type Article struct { Id int `json:"id"` Title string `json:"title"` PubDate mysql.NullTime `json:"pub_date"` Body sql.NullString `json:"body"` User sql.NullInt64 `json:"user"` }
这样的定义是可以work的,但是会有一点奇怪:没谁会用数据库的类型来代替平时的类型。所以,我们可以改一种思路。在解析数据库的时候会有专用的数据库类型字段来接收,但是在返回json的时候有专门的model来使用,这个model用的是普通的类型。
所以,写起来是这样的:
var person Person var personID int64 var password sql.NullString var lastLogin mysql.NullTime var isSuperuser sql.NullBool var userName sql.NullString var firstName sql.NullString var lastName sql.NullString var email sql.NullString var isStaff sql.NullBool var isActive sql.NullBool var dateJoined mysql.NullTime err = ret.Scan( &personID, &password, &lastLogin, &isSuperuser, &userName, &firstName, &lastName, &email, &isStaff, &isActive, &dateJoined, )
上面定义了解析,下面定义model:
type Person struct { ID int64 `json:"id"` Password string `json:"password"` LastLogin *time.Time `json:"last_login"` IsSuperuser bool `json:"is_superuser"` Username string `json:"username"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Email string `json:"email"` IsStaff bool `json:"is_staff"` IsActive bool `json:"is_active"` DateJoined *time.Time `json:"date_joined"` }
有了前两部之后,现在可以装配这些数据了:
person.ID = personID person.Password = If(password.Valid, password.String, "").(string) if tempTime, ok := If(lastLogin.Valid, lastLogin.Time, nil).(*time.Time); ok { person.LastLogin = tempTime } else { person.LastLogin = nil } person.IsSuperuser = If(isSuperuser.Valid, isSuperuser.Bool, false).(bool) person.Username = If(userName.Valid, userName.String, "").(string) person.FirstName = If(firstName.Valid, firstName.String, "").(string) person.LastName = If(lastName.Valid, lastName.String, "").(string) person.Email = If(email.Valid, email.String, "").(string) person.IsStaff = If(isStaff.Valid, isStaff.Bool, false).(bool) person.IsActive = If(isActive.Valid, isActive.Bool, false).(bool) if tempTime, ok := If(dateJoined.Valid, dateJoined.Time, nil).(*time.Time); ok { person.DateJoined = tempTime } else { person.DateJoined = nil }
有一点需要注意的。在golang里类型转换之前需要先做一个type assertion才行,否则报错。而且
nil是不能做类型转换的,比如:
if tempTime, ok := If(dateJoined.Valid, dateJoined.Time, nil).(*time.Time); ok { person.DateJoined = tempTime } else { person.DateJoined = nil }
以上是同sqlite做为数据库是遇到的问题。还有一点,sqlite没有处理时间为空的类型,所以上面使用的是mysql的driver里的
NullTime,奇怪的是用自定义的NullTime不行。懒得深究了,哪位知道的话希望留言。
下面是全部的app代码:
package main import ( "encoding/json" "fmt" "net/http" "time" "database/sql" "log" "github.com/go-sql-driver/mysql" "github.com/labstack/echo" "github.com/labstack/echo/middleware" _ "github.com/mattn/go-sqlite3" ) func main() { // Echo instance e := echo.New() // Middleware e.Use(middleware.Logger()) e.Use(middleware.Recover()) // Routes e.GET("/", hello) // Start server e.Logger.Fatal(e.Start(":1323")) } func hello(c echo.Context) error { ret, err := executeSQL("select id,password,last_login,is_superuser,username,first_name,last_name,email,is_staff,is_active,date_joined from person where id = ?") if err != nil { return c.JSON(http.StatusOK, map[string]string{"error": "Something went wrong when getting data from db"}) } return c.JSON(http.StatusOK, ret) } // Execute sql statement from parameter, which looks like this: // select a, b, c from some_tabble where id = ? // Return a map func executeSQL(sqlStmt string) ([]Person, error) { db, err := sql.Open("sqlite3", "./db.sqlite3") if err != nil { log.Fatal(err) } defer db.Close() stmt, err := db.Prepare(sqlStmt) if err != nil { log.Fatal(err) return nil, err } defer stmt.Close() ret, err := stmt.Query(3) if err != nil { log.Fatal(err) return nil, err } personList := make([]Person, 0) for ret.Next() { var person Person var personID int64 var password sql.NullString var lastLogin mysql.NullTime var isSuperuser sql.NullBool var userName sql.NullString var firstName sql.NullString var lastName sql.NullString var email sql.NullString var isStaff sql.NullBool var isActive sql.NullBool var dateJoined mysql.NullTime err = ret.Scan( &personID, &password, &lastLogin, &isSuperuser, &userName, &firstName, &lastName, &email, &isStaff, &isActive, &dateJoined, ) if err != nil { log.Fatal(err) } person.ID = personID person.Password = If(password.Valid, password.String, "").(string) if tempTime, ok := If(lastLogin.Valid, lastLogin.Time, nil).(*time.Time); ok { person.LastLogin = tempTime } else { person.LastLogin = nil } person.IsSuperuser = If(isSuperuser.Valid, isSuperuser.Bool, false).(bool) person.Username = If(userName.Valid, userName.String, "").(string) person.FirstName = If(firstName.Valid, firstName.String, "").(string) person.LastName = If(lastName.Valid, lastName.String, "").(string) person.Email = If(email.Valid, email.String, "").(string) person.IsStaff = If(isStaff.Valid, isStaff.Bool, false).(bool) person.IsActive = If(isActive.Valid, isActive.Bool, false).(bool) if tempTime, ok := If(dateJoined.Valid, dateJoined.Time, nil).(*time.Time); ok { person.DateJoined = tempTime } else { person.DateJoined = nil } personList = append(personList, person) } j, err := json.Marshal(personList) if err != nil { log.Fatal(err) } fmt.Println(j) return personList, nil }
相关文章推荐
- shell处理—文件汇总到一个文件里,用sqlldr装入数据库这些文件数据都少一个字段而字段内容为这个文件的名字
- java数据库编程--处理大对象数据(处理CLOB数据)
- java中数据库访问方式的不同处理数据总结:
- 手动处理Team Foundation Server 2010 数据仓库和分析服务数据库
- 横瓜先生如何用MDB和XLS等低性能数据库来处理千亿级数据量。
- 3.9关于数据库与Geoserver在处理空间数据的不同意义
- 【数据库】【JDBC】使用JDBC处理MySQL大数据
- 数据库大数据处理---复制(SQLServer)
- 服务器返回数据为nil,null问题处理
- 使用Java来处理C++存储在数据库中的Blob数据。
- Java数据库——处理大数据对象
- 数据库 SQL千万级数据规模处理概要
- SQL-SERVER数据库中的游标、存储过程和触发器 关键词 SQL-SERVER、游标、存储过程、触发器、高效处理数据
- GoLang基础数据类型--->字符串处理大全
- 【Web API系列教程】3.3 — 实战:处理数据(建立数据库)
- Redis 与 数据库处理数据的两种模式
- jabc连接数据库,处理添加数据时的乱码问题
- 关于数据库并发处理数据的问题
- C# 多线程并发处理数据库数据,发送信号等待处理完统一插入
- GoLang基础数据类型--->字符串处理大全