在用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
}

Golang处理数据库的nil数据的更多相关文章

  1. 一分钟上手, 让 Golang 操作数据库成为一种享受

    gorose, 最风骚的 go orm, 拥有链式操作, 开箱即用, 一分钟上手等八大风骚, 让 golang 操作数据库成为一种享受, 妈妈再也看不到我处理数据的痛苦了, 下面就来为大家一一讲解 g ...

  2. 将Oracle数据库中的数据写入Excel

    将Oracle数据库中的数据写入Excel 1.准备工作 Oracle数据库"TBYZB_FIELD_PRESSURE"表中数据如图: Excel模板(201512.xls): 2 ...

  3. OpenLayers添加点【php请求MySQL数据库返回GeoJSON数据】

    php请求MySQL数据库返回GeoJSON数据的实现方法请参见: http://www.cnblogs.com/marost/p/6234514.html OpenLayers[v3.19.1-di ...

  4. Django数据操作F和Q、model多对多操作、Django中间件、信号、读数据库里的数据实现分页

    models.tb.objects.all().using('default'),根据using来指定在哪个库里查询,default是settings中配置的数据库的连接名称. 外话:django中引 ...

  5. EF 连接MySQL 数据库  保存中文数据后乱码问题

    EF 连接MySQL 数据库  保存中文数据后乱码问题 采用Code First 生成的数据库,MySQL数据库中,生成的表的编码格式为***** 发现这个问题后,全部手动改成UTF8(图是另一个表的 ...

  6. java更改数据库中的数据

    不废话,上代码 package com.ningmeng; import java.sql.*; /** * 1:更改数据库中的数据 * @author biexiansheng * */ publi ...

  7. Eclipse中java向数据库中添加数据,更新数据,删除数据

    前面详细写过如何连接数据库的具体操作,下面介绍向数据库中添加数据. 注意事项:如果参考下面代码,需要 改包名,数据库名,数据库账号,密码,和数据表(数据表里面的信息) package com.ning ...

  8. C#-WinForm-ListView-表格式展示数据、如何将数据库中的数据展示到ListView中、如何对选中的项进行修改

    在展示数据库中不知道数量的数据时怎么展示最好呢?--表格 ListView - 表格形式展示数据 ListView 常用属性 HeaderStyle - "详细信息"视图中列标头的 ...

  9. phpexcel的写操作将数据库中的数据导入到excel中

    这个版本据说是可以支持excel2007,但是我使用2007编辑的xlsx是无法获得该库的支持.于是乎我就将它转化为2003.感觉支持地很好. 下面介绍一下具体的使用: require_once('. ...

随机推荐

  1. CodeWarrior 10 配置Jlint初始化文件

    新建一个项目之后,飞思卡尔的仿真器的配置不如德州仪器那么简单.他需要一些配置. 当我们新建一个工程后,可以采取如下步骤配置Jlint: 1.右击工程名,选择属性. 2.在Run/Debug Setti ...

  2. Flipping an Image

    Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resu ...

  3. IDEA报错No Spring WebApplicationInitializer types detected on classpath

    IDEA报错No Spring WebApplicationInitializer types detected on classpath https://my.oschina.net/sprouti ...

  4. Linux /etc/hosts文件

    均为转载 ———————— 1.主机名: 无论在局域网还是INTERNET上,每台主机都有一个IP地址,是为了区分此台主机和彼台主机,也就是说IP地址就是主机的门牌号. 公网:IP地址不方便记忆,所以 ...

  5. pwnable.kr-fd-witeup

    登录进远程电脑,看到flag,查看内容,权限不够失败咯,ls -la看看权限. 欧克,fd用户对flag只用可读权限,但是呢,看到fd用户对fd文件有s权限,它指设置使当前在执行阶段具有文件所有者的权 ...

  6. STM32的命名规范

    STM32F407VET6 STM32F407代表的是芯片的型号后面的字符表示芯片的信息 V这一项代表引脚数,其中T代表36脚,C代表48脚,R代表64脚,V代表100脚,Z代表144脚,I代表176 ...

  7. c# post方法亲测可用

    /// <summary> /// Post接口方法 /// </summary> /// <param name="requestUri">& ...

  8. functools 之 partial(偏函数)

    当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单.当然,decorator(装饰器) 也可以实现, ...

  9. vue中具名插槽的使用

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 1、背景介绍及移动云MAS平台 --短信平台

    目的: 刚开发完成一套短信平台以及一个Web端短信发送系统,短信平台耗时两个周.短信发送系统耗时两个多月,开发使用的技术没什么高科技含量,在此主要是记录下很多情况的处理方案,希望能让大家提出改善方案和 ...