如何将MySQL TIMESTAMP值扫描到time.Time变量中?

huangapple go评论93阅读模式
英文:

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 (
    &quot;fmt&quot;
    &quot;database/sql&quot;
	_&quot;github.com/go-sql-driver/mysql&quot;
	&quot;time&quot;
)

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(&quot;mysql&quot;, &quot;user:@tcp(127.0.0.1:3306)/c9?parseTime=true&quot;)
	if err != nil {
		fmt.Println(err)
	}
	defer db.Close()
	
	// query
	rows, err := db.Query(&quot;SELECT * FROM users WHERE id = ?&quot;, 1)
    if err != nil {
    	fmt.Println(err)
    }
    defer rows.Close()
    
    usr := User{}
    for rows.Next() {
    	err := rows.Scan(&amp;usr.id, &amp;usr.name, &amp;usr.email, &amp;usr.rating, &amp;usr.subscription, &amp;usr.date_registered, &amp;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&gt; 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&gt; 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 &lt;nil&gt;} }

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

See here

答案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(&quot;mysql&quot;, &quot;myuser:mypass@tcp(127.0.0.1:3306)/mydb?parseTime=true&quot;)

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_registeredusr.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.

huangapple
  • 本文由 发表于 2014年10月29日 04:34:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/26617957.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定