文档章节

Database Go and JSON

qgymje
 qgymje
发布于 2016/08/09 14:06
字数 837
阅读 25
收藏 0

在使用Go开发web项目的过程中, 数据库读写操作与JSON格式的输入输出是两块最基础的模块, Go的标准库已经帮我们做了很多, 熟悉database/sql与encoding/json这两个库能帮我们更自在地开发web应用.

但此篇文章抛开基础不说, 只说一些在开发中遇到一些真实存在的痛点.

如何处理Null值?

Go的一大特色就是zero value, 比如int类型的zero value是0, string为"", struct为每个field里各自类型的zero value. 因此在Go的很多ORM处理NULL值时, 都是通过zero value机制入库或出库的, 因此, 使用ORM操作的数据库, 如何没有明确指明, 基本上看不到NULL值. 一个可能为NULL的varchar字段, 存入了""(空字符串).

这里不讨论关于空字符串与NULL的优劣, 而是说明如何处理NULL值.

sql标准库里带了这么几个类型: sql.NullString, sql.NullInt64, sql.NullBool, sql.NullFloat64, 如果在定义struct里field类型的时候, 使用sql.NullString代替string的话, 就可以在数据库里存入NULL值.

通过源码看到, NullString的结构与两个方法:

type NullString struct{
    String string
    Valid bool
}

Scan(value interface{}) error
Value()(driver.Value, error)

Scan实现了sql.Scanner接口, Value实现了driver.Valuer接口. 这两个接口表示数据从Go端与DB端的转换. Scan用于数据从DB转到Go时被调用,也就是说select时用(查看源码); 而Value则由Go转到DB时被调用. 也就是说insert/update时候用(查看源码).

在两个不同领域做数据转换时, 通常用接口来定义, 这是接口的作用, JSON也是同样如此.

有了接口的帮助, 任何实现了这两个接口的类型, 都能在DB与Go之间做转换, 接口建立起了桥梁.

如何处理自定义类型?
 

由上一节可以想到, 如果在想要保存Go自定义类型到DB里, 只需要实现Scanner与Valuer接口, 就像sql.NullString一样.

典型如NullTime(查看源码):

type NullTime struct {
    Time  time.Time
    Valid bool
}

func (nt *NullTime) Scan(value interface{}) error {
    nt.Time, nt.Valid = value.(time.Time)
    return nil
}

func (nt NullTime) Value() (driver.Value, error) {
    if !nt.Valid {
        return nil, nil
    }
    return nt.Time, nil
}

为了让这个类型更好用, 添加一个帮助函数:

func ToNullTime(t time.Time) NullTime {
    return NullTime{Time: t, Valid: !t.IsZero()}
}

自定义类型如何转化成JSON?
 

如果拿一个sql.NullString的类型, 做json.Marshal, 那么得到输出是这样的:

{
    ...
    "column_name" : { "String" : "Hello?", "Valid" : true },
    ...
}
//而我们想要的是:
{
    ...
    "column_name" : "Hello?",
    ...
}
//or
{
    ...
    "column_name" : null,
    ...
}

我们知道, json库有两个标准的接口, json.Marshaler(查看源码) , json.Unmarshaler(查看源码), 如果一个类型实现此两个接口, 则在使用json.Marshal/Unmarshal调用时, 调用此类型的自定义方法:

type NullString struct {
    sql.NullString
}

func(v *NullString) MarshalJSON() ([]byte, error) {
    if v.Valid {
        return json.Marshal(v.String)
    } else {
        return json.Marshal(nil)
    }
}

func (v NullString) UnmarshalJSON(data []byte) error {
    var s *string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    if s != nil {
        v.Valid = true
        v.String = *s
    } else {
        v.Valid = false
    }
    return nil
}

总结

Go语言的接口, 扮演了桥梁的角色, 连接起了Go与其它领域的数据转换, 通过实现标准库的接口, 我们可以让Go的数据类型轻松适应不同数据领域.


[参考]
http://dennissuratna.com/marshalling-nullable-string-db-value-to-json-in-go/

http://blog.carbonfive.com/2015/07/09/there-will-be-sql/

http://marcesher.com/2014/10/13/go-working-effectively-with-database-nulls/

© 著作权归作者所有

共有 人打赏支持
qgymje
粉丝 1
博文 1
码字总数 837
作品 0
松江
程序员
私信 提问
mysql 5.7 JSON 支持

1.首先要保证正确的字符集 2.创建数据库 3.创建表 4.插入数据 5.查询数据

HashTable
2016/09/10
18
0
资料整理——Oracle基本概念、术语(Glossary from Oracle Concepts)——第七部分

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hpdlzu80100/article/details/84871573 将知识凝练成概念的好处是简单、扼要、规范,这对于知识的应用、普及、...

预见未来to50
12/07
0
0
从 PostgreSQL 中以不同形式导出数据--pgclimb

pgclimb 是从 PostgreSQL 中以不同形式将数据导出的工具。 特点: 导出数据至 JSON, JSON Lines, CSV, XLSX, XML 。 使用 Templates 以支持自定义格式(HTML, Markdown, Text)。 使用场合: ...

匿名
2016/09/18
111
0
POSTGRESQL 应用

查看Size 函数名 返回类型 描述 pgcolumnsize(any) int 存储一个指定的数值需要的字节数(可能压缩过) pgdatabasesize(oid) bigint 指定OID的数据库使用的磁盘空间 pgdatabasesize(name) b...

灌直
2016/01/20
16
0
使用oclint分析ios项目

预备:mac os x,安装xcode 安装homebrew http://brew.sh/ 安装xctool brew install xctool 进入项目目录,执行 xctool -sdk iphonesimulator9.2 -project <YourProject.xcodeproj> -sheme <......

紅紅火火
2016/03/22
93
1

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 其实我在地板也睡不着

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @witt-z :分享歌词: 阴天 在不开灯的房间,当所有思绪都一点一点沉淀。 分享莫文蔚的单曲《阴天》: 《阴天》- 莫文蔚 手机党少年们想听歌,...

小小编辑
26分钟前
28
3
微服务分布式事务实现

https://www.processon.com/view/link/5b2144d7e4b001a14d3d2d30

WALK_MAN
今天
3
0
《大漠烟尘》读书笔记及读后感文章3700字

《大漠烟尘》读书笔记及读后感文章3700字: 在这个浮躁的社会里,你有多久没有好好读完一本书了? 我们总觉得自己和别人不一样,所以当看到别人身上的问题时,很少有“反求诸己”,反思自己。...

原创小博客
今天
4
0
大数据教程(9.5)用MR实现sql中的jion逻辑

上一篇博客讲解了使用jar -jar的方式来运行提交MR程序,以及通过修改YarnRunner的源码来实现MR的windows开发环境提交到集群的方式。本篇博主将分享sql中常见的join操作。 一、需求 订单数据表...

em_aaron
今天
3
0
十万个为什么之什么是resultful规范

起源 越来越多的人开始意识到,网站即软件,而且是一种新型的软件。这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点...

尾生
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部