英文:
How to .Scan() a MySQL TIMESTAMP value into a time.Time variable?
问题
我有这段Go代码:
package main
import (
"fmt"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"time"
)
type User struct {
id uint32
name string
email string
rating uint8
subscription uint8
date_registered time.Time
online string
}
// 主入口函数
func main() {
// 设置数据库连接
db, err := sql.Open("mysql", "user:@tcp(127.0.0.1:3306)/c9?parseTime=true")
if err != nil {
fmt.Println(err)
}
defer db.Close()
// 查询
rows, err := db.Query("SELECT * FROM users WHERE id = ?", 1)
if err != nil {
fmt.Println(err)
}
defer rows.Close()
usr := User{}
for rows.Next() {
err := rows.Scan(&usr.id, &usr.name, &usr.email, &usr.rating, &usr.subscription, &usr.date_registered, &usr.online)
if err != nil {
fmt.Println(err)
}
}
fmt.Println(usr)
err = rows.Err()
if err != nil {
fmt.Println(err)
}
}
这是我从MySQL控制台获取的内容:
mysql> describe users;
+-----------------+---------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+-------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
| email | varchar(50) | NO | | NULL | |
| rating | tinyint(3) unsigned | YES | | NULL | |
| subscription | tinyint(3) unsigned | NO | | 0 | |
| date_registered | timestamp | NO | | CURRENT_TIMESTAMP | |
| online | char(1) | NO | | N | |
+-----------------+---------------------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)
mysql> SELECT * FROM users;
+----+------------+-----------------------+--------+--------------+---------------------+--------+
| id | name | email | rating | subscription | date_registered | online |
+----+------------+-----------------------+--------+--------------+---------------------+--------+
| 1 | alakhazamm | abcdefghhhh@gmail.com | NULL | 0 | 2014-10-28 15:37:44 | N |
+----+------------+-----------------------+--------+--------------+---------------------+--------+
1 row in set (0.00 sec)
在.Scan()
之后,fmt.Println(usr)
打印出:
{1 alakhazamm abcdefghhhh@gmail.com 0 0 {0 0 <nil>} }
结构体的最后两个字段是错误的,但我不知道为什么。
我尝试在结构体定义中使用date_registered string
,但在.Scan()
之后得到一个空字符串。
我还在驱动程序的文档中阅读到,?parseTime=true
将MySQL的DATE和DATETIME值解析为time.Time,但他们没有提到我当前使用的TIMESTAMP。
我是否遗漏了重要的东西,还是这是库的一个错误/缺失的功能?
英文:
I have this Go code:
package main
import (
"fmt"
"database/sql"
_"github.com/go-sql-driver/mysql"
"time"
)
type User struct {
id uint32
name string
email string
rating uint8
subscription uint8
date_registered time.Time
online string
}
// main entry point
func main() {
// setup db connection
db, err := sql.Open("mysql", "user:@tcp(127.0.0.1:3306)/c9?parseTime=true")
if err != nil {
fmt.Println(err)
}
defer db.Close()
// query
rows, err := db.Query("SELECT * FROM users WHERE id = ?", 1)
if err != nil {
fmt.Println(err)
}
defer rows.Close()
usr := User{}
for rows.Next() {
err := rows.Scan(&usr.id, &usr.name, &usr.email, &usr.rating, &usr.subscription, &usr.date_registered, &usr.online)
if err != nil {
fmt.Println(err)
}
}
fmt.Println(usr)
err = rows.Err()
if err != nil {
fmt.Println(err)
}
}
This is what I get from MySQL console:
mysql> describe users;
+-----------------+---------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+-------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
| email | varchar(50) | NO | | NULL | |
| rating | tinyint(3) unsigned | YES | | NULL | |
| subscription | tinyint(3) unsigned | NO | | 0 | |
| date_registered | timestamp | NO | | CURRENT_TIMESTAMP | |
| online | char(1) | NO | | N | |
+-----------------+---------------------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)
mysql> SELECT * FROM users;
+----+------------+-----------------------+--------+--------------+---------------------+--------+
| id | name | email | rating | subscription | date_registered | online |
+----+------------+-----------------------+--------+--------------+---------------------+--------+
| 1 | alakhazamm | abcdefghhhh@gmail.com | NULL | 0 | 2014-10-28 15:37:44 | N |
+----+------------+-----------------------+--------+--------------+---------------------+--------+
1 row in set (0.00 sec)
After .Scan()
, fmt.Println(usr)
prints
{1 alakhazamm abcdefghhhh@gmail.com 0 0 {0 0 <nil>} }
The last two fields of the struct are wrong but I have no idea why.
I've tried using date_registered string
in the struct definition, but I get an empty string after .Scan()
.
I've also read in the driver's docs that ?parseTime=true
parses MySQL DATE and DATETIME values into time.Time, but they don't mention TIMESTAMP which is what I'm currently using.
Am I missing something important or is it a bug/missing feature of the library?
答案1
得分: 24
我知道这是一个旧问题,但是在我的Open调用中,我缺少了这个参数:
parseTime=true
英文:
I know this is an old question however I was missing this parameter in my Open call:
parseTime=true
答案2
得分: 12
除了@incognick的回答之外,以下是你可以做的(添加parseTime=true):
db, err := sqlx.Connect("mysql", "myuser:mypass@tcp(127.0.0.1:3306)/mydb?parseTime=true")
如果时间戳/日期时间可能为空,那么你应该使用sql.NullTime作为scan参数,而不是time.Time。
使用sql.NullTime将为你提供一个选项,可以使用var.Valid
标志检查扫描的时间是否为空。如果时间有效且不为空,你可以使用var.Time
来表示。
英文:
In addition to answer by @incognick, here is exactly you can do (add parseTime=true):
db, err := sqlx.Connect("mysql", "myuser:mypass@tcp(127.0.0.1:3306)/mydb?parseTime=true")
If there is a possibility of timestamp/datetime be null, in that case you should use scan parameter as sql.NullTime instead of time.Time.
Using sql.NullTime will provide you option to check if scanned time is null or not using var.Valid
flag. You can use time with var.Time
if it is valid and not null.
答案3
得分: 4
我已经找到错误的原因。
由于数据库中的rating
字段为NULL,扫描器报错:
在第3列进行扫描时出现错误:将字符串"nil"转换为uint8类型时出错:strconv.ParseUint: 解析"nil"时出现无效语法
我已经更新了数据库行,现在usr.date_registered
和usr.online
保存了正确的值。
我猜我需要将MySQL字段设置为NOT NULL,并使用-1来表示未初始化的值。
英文:
I've found the cause of the error.
Since rating
is NULL in the database, the scanner gave the error
> sql: Scan error on column index 3: converting string "nil" to a
> uint8: strconv.ParseUint: parsing "nil": invalid syntax
I've updated the database row and now usr.date_registered
and usr.online
hold the correct values.
I guess I'll have to make the MySQL field NOT NULL and just use -1 to indicate a non-initialised value.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论