为什么在 db.Prepare 之后 `votes` 的值发生了变化?

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

Why the value of `votes` is changed after db.Prepare?

问题

我正在使用http://github.com/Go-SQL-Driver/MySQL。

我想从数据库中获取一个名为votes的值,例如"0000",并将其更新为"1000"。在db.Prepare()之前,它正常工作。但是在此之后,votes的值发生了变化。除了db.Prepare()之外,我没有对它做任何操作。我的代码如下:

func Vote(_type, did int, username string) (isSucceed bool) {
    db := lib.OpenDb()
    defer db.Close()

    stmt, err := db.Prepare(
        `SELECT votes
        FROM users
        WHERE username = ?`)
    lib.CheckErr(err)

    res := stmt.QueryRow(username)
    stmt.Close()

    var votes Votes
    res.Scan(&votes)
    fmt.Println(votes)//输出:[48 48 48 48]
    fmt.Println(string(votes))//输出:0000

    isSucceed = votes.add(VoteType(_type), 1)
    fmt.Println(votes)//输出:[49 48 48 48]
    fmt.Println(string(votes))//输出:1000

    //v := []byte{[]byte(votes)[0], []byte(votes)[1], []byte(votes)[2], []byte(votes)[3]}

    if isSucceed {
        //更新用户的投票数
        stmt, err := db.Prepare(
            `UPDATE users
            SET votes = ?
            WHERE username = ?`)
        lib.CheckErr(err)

        fmt.Println(votes)//输出:[4 254 0 0]
        fmt.Println(string(votes))//输出:[EOT]□[NUL][NUL]
        //_, _ = stmt.Exec(v, username)
        _, _ = stmt.Exec(votes, username)
        stmt.Close()

        //插入投票数据
        stmt, err = db.Prepare(
            `INSERT votes
            SET did = ?, username = ?, date = ?`)
        lib.CheckErr(err)

        today := time.Now()
        _, _ = stmt.Exec(did, username, today)
        stmt.Close()
    }
    
    return
}

Votes类型定义如下:

type Votes []byte
type VoteType int

func (this *Votes) add(_type VoteType, num int) (isSucceed bool) {
    if []byte(*this)[_type] > VOTE_MAX-1 { //超过最大值
        isSucceed = false
    } else {
        []byte(*this)[_type]++
        isSucceed = true
    }
    return
}

最后,我将votes的值复制到v中,它正常工作。我无法理解为什么votes的值会发生变化。我的代码有什么问题吗?任何帮助将不胜感激。

英文:

I am using http://github.com/Go-SQL-Driver/MySQL

I want to get a value votes like "0000" from database and update it into "1000". Before db.Prepare() it works normally. But after it, the value of votes is changed. I didn't do anything with it except db.Prepare(). My code is

func Vote(_type, did int, username string) (isSucceed bool) {
db := lib.OpenDb()
defer db.Close()
stmt, err := db.Prepare(
`SELECT votes
FROM users
WHERE username = ?`)
lib.CheckErr(err)
res := stmt.QueryRow(username)
stmt.Close()
var votes Votes
res.Scan(&votes)
fmt.Println(votes)//output: [48 48 48 48]
fmt.Println(string(votes))//output: 0000
isSucceed = votes.add(VoteType(_type), 1)
fmt.Println(votes)//output: [49 48 48 48]
fmt.Println(string(votes))//output: 1000
//v := []byte{[]byte(votes)[0], []byte(votes)[1], []byte(votes)[2], []byte(votes)[3]}
if isSucceed {
//Update user votes
stmt, err := db.Prepare(
`UPDATE users
SET votes = ?
WHERE username = ?`)
lib.CheckErr(err)
fmt.Println(votes)//output: [4 254 0 0]
fmt.Println(string(votes))//output: [EOT]□[NUL][NUL]
//_, _ = stmt.Exec(v, username)
_, _ = stmt.Exec(votes, username)
stmt.Close()
//Insert the vote data
stmt, err = db.Prepare(
`INSERT votes
SET did = ?, username = ?, date = ?`)
lib.CheckErr(err)
today := time.Now()
_, _ = stmt.Exec(did, username, today)
stmt.Close()
}
return
}

the Votes type is :

type Votes []byte
type VoteType int
func (this *Votes) add(_type VoteType, num int) (isSucceed bool) {
if []byte(*this)[_type] > VOTE_MAX-1 { //beyond
isSucceed = false
} else {
[]byte(*this)[_type]++
isSucceed = true
}
return
}

Finally I copy the value from votes into v and it works well. I can not understand why the value of votes is changed. Is there anything wrong with my code? Any help would be appreciated.

答案1

得分: 0

我认为问题出在以下语句:

res.Scan(&votes)

应该改为:

res.Scan((*[]byte)(&votes))

你传递给Scan的Votes不会被识别为[]byte,除非你进行断言。

下面是一个清楚展示识别问题的示例:

package main
import "fmt"
type BYTES []byte
func test(v interface{}) {
b, ok := v.(*[]byte)
fmt.Println(b, ok)
}
func main() {
p := BYTES("hello")
test(&p)
test((*[]byte)(&p))
}

以上代码输出:

<nil> false
&[104 101 108 108 111] true
英文:

I think the problem lies in the statement:

res.Scan(&amp;votes)

which should be:

res.Scan((*[]byte)(&amp;votes))

the *Votes you pass on to Scan will not be identified as *[]byte unless you make an assertion.

Here is an example that clearly shows the identification problem:

package main
import &quot;fmt&quot;
type BYTES []byte
func test(v interface{}) {
b, ok := v.(*[]byte)
fmt.Println(b, ok)
}
func main() {
p := BYTES(&quot;hello&quot;)
test(&amp;p)
test((*[]byte)(&amp;p))
}

The code above prints:

&lt;nil&gt; false
&amp;[104 101 108 108 111] true

huangapple
  • 本文由 发表于 2013年8月9日 01:01:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/18131836.html
匿名

发表评论

匿名网友

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

确定