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('. ...
随机推荐
- Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1) C(二分+KMP)
http://codeforces.com/contest/1129/problem/C #include<bits/stdc++.h> #define fi first #define ...
- Selenium+Java的TestNG测试报告优化
本博主很懒,但学习很勤快,一般能从博客园直接转载的东西,本博主绝不动手写,无奈Selenium+java生成的测试报告在百度上搜索..反正我是没有看到.后来才知道TestNG它可以自动生成测试报告,但 ...
- Flipping an Image
Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resu ...
- Spring:MVC
摘要 Spring MVC 是一个开源的.基于MVC架构的WEB应用框架.这里记录MVC模型的概念以及Spring MVC 的请求处理流程. 关键词:Spring MVC 一.什么是Spring MV ...
- 下拉js的实现
这个JS是出自一个浴室柜网站 $(document).ready(function(){ $(".side_nav_3").hover(function() { $(this).f ...
- c++ vector push_back对象的时候存起来的是拷贝
比如 class C1; vector<C1> vec;C1* p=new C1;vec v1;v1.push_back(&(*p));delete p; 这里,传进函数的是引用, ...
- 如何看iOS崩溃日志
重点:Triggered by Thread这句话后边的线程号,快速定位问题出现在那个线程,是否是你的锅:Triggered by Thread所指的线程表示导致异常.崩溃的线程 下边内容转自简书 简 ...
- 4-19 css属性
1. margin 简写属性在一个声明中设置所有外边距属性.该属性可以有 1 到 4 个值. 说明 这个简写属性设置一个元素所有外边距的宽度,或者设置各边上外边距的宽度. 块级元素的垂直相邻外边距会合 ...
- Git冲突标记介绍
<<<<<<< head 是指你本地的分支的 <<<<<<< HEADb789=======b45678910> ...
- Linux驱动之触摸屏程序编写
本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 ...