Golang调用MySQL函数

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

golang calling mysql function

问题

我有一个现有的MySQL表,它使用MySQL的UUID_SHORT()函数生成唯一的ID。表的简化版本如下:

  1. CREATE TABLE `users` (
  2. `user_uuid` bigint(20) unsigned NOT NULL,
  3. `user_name` varchar(64) NOT NULL
  4. );

要创建一个新用户,可以使用以下语句:

  1. INSERT INTO users (user_uuid, user_name) VALUES (UUID_SHORT(), "new user name");

我开始使用gorm实现数据库模型,但不知道如何告诉gorm和database/sql在创建User的新实例时调用UUID_SHORT()。

在model/users.go文件中:

  1. package model
  2. type User struct {
  3. UserUUID uint64 `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
  4. UserName string `sql:"notnull"`
  5. }
  6. func (user User) TableName() string {
  7. return "users"
  8. }

在model/users_test.go文件中:

  1. package model_test
  2. import (
  3. "testing"
  4. ".../model"
  5. ".../model/testutil"
  6. )
  7. func TestUserCreate(t *testing.T) {
  8. user := model.User{
  9. // UserUUID: **在这里如何调用UUID_SHORT()?**,
  10. UserName: "Go Test",
  11. }
  12. // testutil.DB是gorm.Open("mysql", ...)的成功结果
  13. testutil.DB.Create(&user)
  14. }

在保存实例时,如何调用UUID_SHORT()来为user_uuid列生成值?

英文:

I have an existing mysql table, which uses mysql's UUID_SHORT() function to generate unique IDs. A simplified version of the table:

  1. CREATE TABLE `users` (
  2. `user_uuid` bigint(20) unsigned NOT NULL,
  3. `user_name` varchar(64) NOT NULL
  4. );

And a new user would be created via:

  1. INSERT INTO users (user_uuid, user_name) values (UUID_SHORT(), "new user name");

I started to implement the DBs model using gorm and I'm drawing a blank on how to tell gorm and database/sql to call UUID_SHORT() when a new instance of User is created.

From model/users.go:

  1. package model
  2. type User struct {
  3. UserUUID uint64 `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
  4. UserName string `sql:"notnull"`
  5. }
  6. func (user User) TableName() string {
  7. return "users"
  8. }

From model/users_test.go:

  1. package model_test
  2. import (
  3. "testing"
  4. ".../model"
  5. ".../model/testutil"
  6. )
  7. func TestUserCreate(t *testing.T) {
  8. user := model.User{
  9. // UserUUID: **HOW DO I CALL UUID_SHORT() HERE?**,
  10. UserName: "Go Test",
  11. }
  12. // testutil.DB is the successful result of gorm.Open("mysql", ...)
  13. testutil.DB.Create(&user)
  14. }

How can I call UUID_SHORT() for the user_uuid column when the instance is saved?

答案1

得分: 3

为了在model.User调用中使用MySQL的UUID_SHORT()函数,似乎需要在达到testutil.DB.Create(&user)这一行之前,对数据库进行额外的SQL调用。

使用gorm来实现MySQL的UUID_SHORT()调用可能是一个不错的选择,但这可能需要更多的工作,仅仅是为了映射一个单独的行值(在这种情况下是user_uuid),以便在model.User中使用(可能需要额外的struct来处理UUID_SHORT())。

因此,使用一个更简单的方法可能会有所帮助。以下代码是一个基本的(尽管可能不太好的)示例,展示了如何使用sql来获取UUID_SHORT()(在这种情况下使用了get_uuid_short()自定义函数):

  1. package model_test
  2. import (
  3. "database/sql"
  4. _ "github.com/go-sql-driver/mysql"
  5. "github.com/jinzhu/gorm"
  6. "github.com/stretchr/testify/assert"
  7. "log"
  8. "testing"
  9. )
  10. type User struct {
  11. UserUUID uint64 `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
  12. UserName string `sql:"notnull"`
  13. }
  14. func (user User) TableName() string {
  15. return "users"
  16. }
  17. func get_uuid_short() uint64 {
  18. var uuid_short uint64
  19. /* 使用`sql`包连接到数据库 */
  20. db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/uuid_test")
  21. if err != nil {
  22. log.Fatal(err)
  23. }
  24. /* 查询UUID_SHORT() */
  25. rows, err := db.Query("select UUID_SHORT()")
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. defer db.Close()
  30. /* 获取uuid_short的值 */
  31. for rows.Next() {
  32. err := rows.Scan(&uuid_short)
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. }
  37. return uuid_short
  38. }
  39. func TestUserCreate(t *testing.T) {
  40. user := User{
  41. UserUUID: get_uuid_short(), /* 获取下一个UUID_SHORT()的值 */
  42. UserName: "Go Test",
  43. }
  44. db, err := gorm.Open("mysql", "username:password@/uuid_test?charset=utf8&parseTime=True&loc=Local")
  45. db.Create(&user)
  46. assert.Nil(t, err)
  47. }

在MySQL表中的结果如下:

  1. mysql> select * from users;
  2. +-------------------+-----------+
  3. | user_uuid | user_name |
  4. +-------------------+-----------+
  5. | 24070794506141712 | Go Test |
  6. | 24070794506141713 | Go Test |
  7. | 24070794506141714 | Go Test |
  8. +-------------------+-----------+
  9. 3 rows in set (0.00 sec)

注意:此代码可能无法处理多个用户同时调用get_uuid_short()的情况(尽管MySQL可能已经提供了处理这种情况的方法)。

英文:

In order to make a call to MySQL's UUID_SHORT() in your model.User call, it would seem that you'd need to make an additional SQL call to the database before reaching the testutil.DB.Create(&user) line at some point.

It might be nice to find a way to use gorm for the MySQL UUID_SHORT() call itself, but that might end up requiring more work just to map a single row value (user_uuid in this case) for use in your model.User (possibly requiring an additional struct just for UUID_SHORT()).

Therefore, using a simpler approach might help. The following code is a basic (though perhaps poor*) example of how UUID_SHORT() could be found using the sql package (specifically with the get_uuid_short() user-defined function, in this case):

  1. package model_test
  2. import (
  3. "database/sql"
  4. _ "github.com/go-sql-driver/mysql"
  5. "github.com/jinzhu/gorm"
  6. "github.com/stretchr/testify/assert"
  7. "log"
  8. "testing"
  9. )
  10. type User struct {
  11. UserUUID uint64 `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
  12. UserName string `sql:"notnull"`
  13. }
  14. func (user User) TableName() string {
  15. return "users"
  16. }
  17. func get_uuid_short() uint64 {
  18. var uuid_short uint64
  19. /* connect to db using `sql` package */
  20. db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/uuid_test")
  21. if err != nil {
  22. log.Fatal(err)
  23. }
  24. /* select UUID_SHORT() */
  25. rows, err := db.Query("select UUID_SHORT()")
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. defer db.Close()
  30. /* get value of uuid_short */
  31. for rows.Next() {
  32. err := rows.Scan(&uuid_short)
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. }
  37. return uuid_short
  38. }
  39. func TestUserCreate(t *testing.T) {
  40. user := User{
  41. UserUUID: get_uuid_short(), /* get next UUID_SHORT() value */
  42. UserName: "Go Test",
  43. }
  44. db, err := gorm.Open("mysql", "username:password@/uuid_test?charset=utf8&parseTime=True&loc=Local")
  45. db.Create(&user)
  46. assert.Nil(t, err)
  47. }

With results like this in the MySQL table:

  1. mysql> select * from users;
  2. +-------------------+-----------+
  3. | user_uuid | user_name |
  4. +-------------------+-----------+
  5. | 24070794506141712 | Go Test |
  6. | 24070794506141713 | Go Test |
  7. | 24070794506141714 | Go Test |
  8. +-------------------+-----------+
  9. 3 rows in set (0.00 sec)

*Note: This code might not address times where multiple users are concurrently calling get_uuid_short() (though MySQL may already provide a way to deal with this).

huangapple
  • 本文由 发表于 2014年12月30日 02:24:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/27694020.html
匿名

发表评论

匿名网友

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

确定