Golang处理数据库的nil数据
在用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数据的更多相关文章
- 一分钟上手, 让 Golang 操作数据库成为一种享受
gorose, 最风骚的 go orm, 拥有链式操作, 开箱即用, 一分钟上手等八大风骚, 让 golang 操作数据库成为一种享受, 妈妈再也看不到我处理数据的痛苦了, 下面就来为大家一一讲解 g ...
- 将Oracle数据库中的数据写入Excel
将Oracle数据库中的数据写入Excel 1.准备工作 Oracle数据库"TBYZB_FIELD_PRESSURE"表中数据如图: Excel模板(201512.xls): 2 ...
- OpenLayers添加点【php请求MySQL数据库返回GeoJSON数据】
php请求MySQL数据库返回GeoJSON数据的实现方法请参见: http://www.cnblogs.com/marost/p/6234514.html OpenLayers[v3.19.1-di ...
- Django数据操作F和Q、model多对多操作、Django中间件、信号、读数据库里的数据实现分页
models.tb.objects.all().using('default'),根据using来指定在哪个库里查询,default是settings中配置的数据库的连接名称. 外话:django中引 ...
- EF 连接MySQL 数据库 保存中文数据后乱码问题
EF 连接MySQL 数据库 保存中文数据后乱码问题 采用Code First 生成的数据库,MySQL数据库中,生成的表的编码格式为***** 发现这个问题后,全部手动改成UTF8(图是另一个表的 ...
- java更改数据库中的数据
不废话,上代码 package com.ningmeng; import java.sql.*; /** * 1:更改数据库中的数据 * @author biexiansheng * */ publi ...
- Eclipse中java向数据库中添加数据,更新数据,删除数据
前面详细写过如何连接数据库的具体操作,下面介绍向数据库中添加数据. 注意事项:如果参考下面代码,需要 改包名,数据库名,数据库账号,密码,和数据表(数据表里面的信息) package com.ning ...
- C#-WinForm-ListView-表格式展示数据、如何将数据库中的数据展示到ListView中、如何对选中的项进行修改
在展示数据库中不知道数量的数据时怎么展示最好呢?--表格 ListView - 表格形式展示数据 ListView 常用属性 HeaderStyle - "详细信息"视图中列标头的 ...
- phpexcel的写操作将数据库中的数据导入到excel中
这个版本据说是可以支持excel2007,但是我使用2007编辑的xlsx是无法获得该库的支持.于是乎我就将它转化为2003.感觉支持地很好. 下面介绍一下具体的使用: require_once('. ...
随机推荐
- python day07笔记总结
2019.4.4 S21 day07笔记总结 一.深浅拷贝 1.copy.copy() 浅拷贝 deep.copy() 深拷贝 2.一般情况 1.str/int/bool 是不可变类型 ...
- for循环 && for-each
Effective Java 第46条for-each循环优先于传统for循环 问题: 使用for循环来遍历集合或者是数组可以借助迭代器和索引变量.但是,如果出现循环嵌套的时候很容易引起混乱. 例如: ...
- heat-engine组件
1.heat-engine启动一个rpc server端,EngineService在初始化时加载heat.clients插件和初始化env, env中包括各种资源关键字对应的映射类和constrai ...
- WEBLOGIC because another WebLogic Server instance is already using this directory
错误提示:because another WebLogic Server instance is already using this directory 原因:ldap目录数据库文件被锁定,可能是w ...
- 使用c#调整图片质量
//参数: 原始图片,保存路径,压缩比 private void CompressImage(MagickNet.Image img,string toPath, long ratio) { usin ...
- python windows环境响铃
import winsound winsound.Beep(600,1000) #其中600表示声音大小,1000表示发生时长,1000为1秒
- Centos 7 docker 启动容器 iptables 报 No chain/target/match by that name
我也遇到这个问题,原因时启动docker服务时没有启动iptables服务导致的(有些docker需要再iptables开放有些端口)解决方法1.启动iptables服务 CentOS 7 以下版本 ...
- Mybatis常用代码
以下使用的数据库是Mysql. Mybatis动态Sql: Mapper.xml如下: <select id="selectOrderList" resultMap=&quo ...
- 一些用Css实现的效果
今天写一个笔试题,其中有一个是用css实现直角梯形的效果,我给出的答案是: <style> .wrap{ width: 100px; height: 50px; border-top:90 ...
- VS2017 连接Linux
喜欢测试各种工具. 注意选择 使用C++的Linux开发 ! 配置ssh连接 工具->选项 添加ssh连接. 添加头文件 我的路径是:C:\Program Files (x86)\Microso ...