å¨ç°代软件å¼ÂÃ¥ÂÂä¸Âï¼Âæ°æ®åºÂæ®æ¼ÂçÂÂè³åÂ
³éÂÂè¦ÂçÂÂè§Âè²ï¼Âç¨äºÂÃ¥ÂÂå¨åÂÂ管çÂÂåºÂç¨ç¨ÂåºÂçÂÂæ°æ®ãÂÂéÂÂ对ä¸ÂÃ¥ÂÂçÂÂæ°æ®åºÂç³»ç»Âï¼Âå¼ÂÃ¥ÂÂ人åÂÂéÂÂ常éÂÂè¦Â使ç¨ç¹å®ÂçÂÂæ°æ®åºÂ驱å¨æÂ¥æÂÂä½Âæ°æ®åºÂï¼Âè¿Âå¾Âå¾ÂéÂÂè¦Âå¼ÂÃ¥ÂÂ人åÂÂæÂÂæ¡ä¸ÂÃ¥ÂÂçÂÂ驱å¨ç¼Âç¨ÂæÂ¥å£ãÂÂå¨ Go è¯Âè¨Âä¸Âï¼Â好å¨æÂÂä¸Â个åÂÂ为 database/sql
çÂÂæ ÂÃ¥ÂÂåºÂï¼ÂæÂÂä¾ÂäºÂç»Âä¸ÂçÂÂç¼Âç¨ÂæÂ¥å£ï¼Â使å¼ÂÃ¥ÂÂ人åÂÂè½å¤Â以ä¸Âç§ÂéÂÂç¨çÂÂæ¹å¼Âä¸ÂÃ¥ÂÂç§ÂÃ¥Â
³ç³»åÂÂæ°æ®åºÂè¿Âè¡Â交äºÂãÂÂ
æ¦Â念
database/sql
Ã¥ÂÂ
éÂÂè¿ÂæÂÂä¾Âç»Âä¸ÂçÂÂç¼Âç¨ÂæÂ¥å£ï¼Âå®Âç°äºÂ对ä¸ÂÃ¥ÂÂæ°æ®åºÂ驱å¨çÂÂæ½象ãÂÂ
å®ÂçÂÂ大è´åÂÂçÂÂå¦Âä¸Âï¼Â
-
Driver
æÂ¥å£å®Âä¹Âï¼Âdatabase/sql/driver
å ä¸Âå®Âä¹ÂäºÂä¸Â个Driver
æÂ¥å£ï¼Â该æÂ¥å£ç¨äºÂ表示ä¸Â个æ°æ®åºÂ驱å¨ãÂÂ驱å¨å¼ÂÃ¥ÂÂè éÂÂè¦Âå®Âç°该æÂ¥å£æÂ¥æÂÂä¾Âä¸Âç¹å®Âæ°æ®åºÂçÂÂ交äºÂè½åÂÂã -
Driver
注åÂÂï¼Â驱å¨å¼ÂÃ¥ÂÂè éÂÂè¦Âå¨ç¨ÂåºÂÃ¥ÂÂå§ÂÃ¥ÂÂé¶段ï¼ÂéÂÂè¿Âè°Âç¨database/sql
å æÂÂä¾ÂçÂÂsql.Register()
æ¹æ³Âå°Âèª己çÂÂ驱å¨注åÂÂå°database/sql
ä¸ÂãÂÂè¿Âæ ·ï¼Âdatabase/sql
å°±è½å¤Âè¯Âå«åÂÂ使ç¨该驱å¨ã -
æ°æ®åºÂè¿Âæ¥池管çÂÂï¼Â
database/sql
ç»´æ¤äºÂä¸Â个æ°æ®åºÂè¿Âæ¥池ï¼Âç¨äºÂ管çÂÂæ°æ®åºÂè¿ÂæÂ¥ãÂÂå½ÂéÂÂè¿Âsql.Open()
æÂÂå¼Âä¸Â个æ°æ®åºÂè¿ÂæÂ¥æ¶ï¼Âdatabase/sql
ä¼Âå¨åÂÂéÂÂçÂÂæ¶æºè°Âç¨注åÂÂçÂÂ驱å¨æÂ¥åÂÂ建ä¸Â个堷ä½ÂçÂÂè¿ÂæÂ¥ï¼Â并å°Â堶添å å°è¿Âæ¥池ä¸ÂãÂÂè¿Âæ¥池ä¼Âè´Âè´£è¿ÂæÂ¥çÂÂå¤Âç¨ãÂÂ管çÂÂÃ¥ÂÂç»´æ¤工ä½Âï¼Â并ä¸Âè¿Âæ¯并åÂÂå®Âå ¨çÂÂã -
ç»Âä¸ÂçÂÂç¼Âç¨ÂæÂ¥å£ï¼Â
database/sql
å®Âä¹ÂäºÂä¸Âç»Âç»Âä¸ÂçÂÂç¼Âç¨ÂæÂ¥å£ä¾Âç¨æ·使ç¨ï¼Âå¦ÂPrepare()
ãÂÂExec()
Ã¥ÂÂQuery()
çÂÂæ¹æ³Âï¼Âç¨äºÂÃ¥ÂÂ夠SQL è¯Âå¥ãÂÂæ§衠SQL è¯Âå¥åÂÂæ§è¡Âæ¥询çÂÂæÂÂä½ÂãÂÂè¿ÂäºÂæ¹æ³Âä¼ÂæÂ¥æ¶åÂÂæ°并è°Âç¨åºÂå±Â驱å¨çÂÂç¸åºÂæ¹æ³ÂæÂ¥æ§è¡Âå®Âé çÂÂæ°æ®åºÂæÂÂä½Âã -
æÂ¥å£æ¹æ³ÂçÂÂå®Âç°ï¼Â驱å¨å¼ÂÃ¥ÂÂè éÂÂè¦Âå®Âç°
database/sql/driver
ä¸Âå®Âä¹ÂçÂÂä¸ÂäºÂæÂ¥å£æ¹æ³Âï¼Â以æ¤æÂ¥æ¯æÂÂä¸Âå±Âdatabase/sql
å æÂÂä¾ÂçÂÂPrepare()
ãÂÂExec()
Ã¥ÂÂQuery()
çÂÂæ¹æ³Âï¼Â以æÂÂä¾ÂåºÂå±Âæ°æ®åºÂçÂÂå ·ä½Âå®Âç°ãÂÂå½Âdatabase/sql
è°Âç¨è¿ÂäºÂæ¹æ³Âæ¶ï¼Âå®Âé ä¸Âä¼Âè°Âç¨注åÂÂçÂÂ驱å¨çÂÂç¸åºÂæ¹æ³ÂæÂ¥æ§è¡Âå ·ä½ÂçÂÂæ°æ®åºÂæÂÂä½ÂãÂÂ
éÂÂè¿Â以ä¸ÂçÂÂæºå¶ï¼Âdatabase/sql
Ã¥ÂÂ
è½å¤Âå®Âç°对ä¸ÂÃ¥ÂÂæ°æ®åºÂ驱å¨çÂÂç»Âä¸Âå°Âè£Â
Ã¥ÂÂè°Âç¨ãÂÂç¨æ·å¯以使ç¨ç¸åÂÂçÂÂç¼Âç¨ÂæÂ¥å£æÂ¥è¿Âè¡Âæ°æ®åºÂæÂÂä½Âï¼Âæ éÂÂÃ¥Â
³å¿ÂåºÂå±Â驱å¨çÂÂÃ¥Â
·ä½Âç»ÂèÂÂãÂÂè¿Âç§Â设计使å¾Â代ç Âæ´åÂ
·å¯移æ¤Âæ§åÂÂçµ活æ§ï¼Âæ¹便åÂÂæ¢åÂÂéÂÂéÂ
Âä¸ÂÃ¥ÂÂçÂÂæ°æ®åºÂãÂÂ
ç¹ç¹
database/sql
Ã¥Â
·æÂÂå¦Âä¸Âç¹ç¹ï¼Â
-
ç»Âä¸ÂçÂÂç¼Âç¨ÂæÂ¥å£ï¼Â
database/sql
åºÂæÂÂä¾ÂäºÂä¸Âç»Âç»Âä¸ÂçÂÂæÂ¥å£ï¼Â使å¾Âå¼ÂÃ¥ÂÂ人åÂÂå¯以使ç¨ç¸åÂÂçÂÂæ¹å¼ÂæÂÂä½Âä¸ÂÃ¥ÂÂçÂÂæ°æ®åºÂï¼ÂèÂÂä¸ÂéÂÂè¦Âå¦习ç¹å®Âæ°æ®åºÂç APIã -
驱å¨æ¯æÂÂï¼ÂéÂÂè¿Â导堥第ä¸Âæ¹æ°æ®åºÂ驱å¨ç¨ÂåºÂï¼Â
database/sql
å¯以ä¸Âå¤Âç§Â常è§ÂçÂÂ堳系åÂÂæ°æ®åºÂç³»ç»Âè¿Âè¡Â交äºÂï¼Â妠MySQLãÂÂPostgreSQLãÂÂSQLite çÂÂã -
é¢Âé² SQL 注堥ï¼Â
database/sql
åºÂéÂÂè¿Â使ç¨é¢Âç¼Âè¯Âè¯Âå¥åÂÂÃ¥ÂÂæ°åÂÂæ¥询çÂÂæÂÂæ¯ï¼ÂæÂÂæÂÂé¢Âé²亠SQL 注堥æÂȌÂȋ -
æ¯æÂÂäºÂå¡ï¼ÂäºÂå¡æ¯ä¸Â个ä¼Âç§Âç SQL å 忠å¤ÂÃ¥ÂÂè½ãÂÂ
Ã¥ÂÂå¤Â
为äºÂæ¼Â示 database/sql
ç¨æ³Âï¼ÂæÂÂÃ¥ÂÂå¤ÂäºÂå¦Â丠MySQL æ°æ®åºÂ表ï¼Â
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL COMMENT 'ç¨æ·åÂÂ',
`email` varchar(255) NOT NULL DEFAULT '' COMMENT 'é®箱',
`age` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'å¹´é¾Â',
`birthday` datetime DEFAULT NULL COMMENT 'çÂÂæÂÂ¥',
`salary` varchar(128) DEFAULT NULL COMMENT 'èª水',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `u_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ç¨æ·表';
ä½ å¯以使ç¨ MySQL å½令è¡ÂæÂÂå¾形åÂÂ工堷åÂÂ建è¿Â张表ãÂÂ
è¿ÂæÂ¥æ°æ®åºÂ
è¦Â使ç¨ database/sql
æÂÂä½Âæ°æ®åºÂï¼Âé¦ÂÃ¥Â
Âè¦Â建ç«Âä¸Âæ°æ®åºÂçÂÂè¿ÂæÂ¥ï¼Â
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql",
"user:password@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local")
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
å 为æÂÂ们è¦Âè¿ÂæÂÂ¥ MySQL æ°æ®åºÂï¼ÂæÂÂ以éÂÂè¦Â导åÂ
Â¥ MySQL æ°æ®åºÂ驱å¨ github.com/go-sql-driver/mysql
ãÂÂdatabase/sql
ç± Go è¯Âè¨Âå®Âæ¹å¢éÂÂ设计ï¼ÂèÂÂæ°æ®åºÂ驱å¨ç¨ÂåºÂÃ¥ÂÂç±社åº维æ¤ï¼ÂÃ¥Â
¶ä»ÂÃ¥Â
³ç³»åÂÂæ°æ®åºÂ驱å¨åÂÂ表å¯å¨è¿ÂéÂÂæÂ¥çÂÂãÂÂ
ä¸Âæ°æ®åºÂ建ç«Âè¿ÂæÂ¥çÂÂ代ç ÂéÂÂ常ç®ÂÃ¥ÂÂï¼ÂåªéÂÂè°Âç¨ sql.Open()
å½æ°å³å¯ãÂÂå®ÂæÂ¥æ¶两个åÂÂæ°ï¼Â驱å¨åÂÂ称å DSNãÂÂ
è¿ÂéÂÂ驱å¨åÂÂ称为 mysql
ï¼Âdatabase/sql
ä¹ÂæÂÂ以è½å¤Âè¯Âå«è¿Â个驱å¨åÂÂ称ï¼Âæ¯å 为å¨å¿åÂÂ导åÂ
Â¥ github.com/go-sql-driver/mysql
æ¶ï¼Âè¿Â个åºÂÃ¥ÂÂ
é¨è°Âç¨亠sql.Register
å°ÂÃ¥Â
¶æ³¨åÂÂç»Â亠database/sql
ãÂÂ
func init() {
sql.Register("mysql", &MySQLDriver{})
}
å¨ Go è¯Âè¨Âä¸Âï¼Âä¸Â个åÂÂ
ç init
æ¹æ³Âä¼Âå¨导åÂ
¥æ¶ä¼Â被èªå¨è°Âç¨ï¼Âè¿ÂéÂÂå®ÂæÂÂäºÂ驱å¨ç¨ÂåºÂçÂÂ注åÂÂãÂÂè¿Âæ ·å¨è°Âç¨ sql.Open()
æ¶æÂÂè½æ¾å° mysql
驱å¨ãÂÂ
第äºÂ个åÂÂæ° DSN Ã¥Â
¨ç§° Data Source Name
ï¼Âæ°æ®åºÂçÂÂæºÂÃ¥ÂÂ称ï¼ÂÃ¥Â
¶æ ¼å¼Âå¦Âä¸Âï¼Â
username:password@protocol(address)/dbname?param=value
ä¸Âé¢æ¯æÂÂ们æÂÂä¾Âç DSN Ã¥ÂÂé¨åÂÂ解éÂÂï¼Â
-
user:password
ï¼Âæ°æ®åºÂçÂÂç¨æ·åÂÂÃ¥ÂÂå¯Âç ÂãÂÂæ ¹æ®å®Âé æ åÂ括Âä½ éÂÂè¦Â使ç¨你èª己çÂÂç¨æ·åÂÂÃ¥ÂÂå¯Âç Âã -
tcp(127.0.0.1:3306)
ï¼Âè¿ÂæÂ¥æ°æ®åºÂæÂÂå¡å¨çÂÂÃ¥ÂÂè®®ãÂÂæ°æ®åºÂæÂÂå¡å¨çÂÂå°åÂÂÃ¥ÂÂ端å£å·ãÂÂå¨è¿Â个ä¾ÂÃ¥ÂÂä¸Âï¼Â使ç¨çÂÂæ¯æŒ°主æº127.0.0.1
å MySQL é»Â认端å£å·3306
ãÂÂä½ å¯以根æ®å®Âé æ åµ修æ¹为你èª己çÂÂæ°æ®åºÂæÂÂå¡å¨å°åÂÂÃ¥ÂÂ端å£å·ã -
/demo
ï¼Âæ°æ®åºÂçÂÂÃ¥ÂÂ称ãÂÂå¨è¿Â个ä¾ÂÃ¥ÂÂä¸Âï¼Âæ°æ®åºÂÃ¥ÂÂ称æ¯demo
ãÂÂä½ å¯以根æ®å®Âé æ åµ修æ¹为你èª己çÂÂæ°æ®åºÂÃ¥ÂÂ称ã -
charset=utf8mb4
ï¼ÂæÂÂå®Âæ°æ®åºÂçÂÂÃ¥ÂÂ符éÂÂ为UTF-8
ãÂÂè¿ÂéÂÂ使ç¨çÂÂæ¯UTF-8
çÂÂÃ¥ÂÂä½ÂUTF-8mb4
ï¼Âæ¯æÂÂæ´广æ³ÂçÂÂÃ¥ÂÂ符èÂÂå´ã -
parseTime=true
ï¼Âå¯ç¨æ¶é´解æÂÂãÂÂè¿Â个åÂÂæ°使å¾Âæ°æ®åºÂ驱å¨ç¨ÂåºÂè½å¤Âå°Âæ°æ®åºÂä¸ÂçÂÂæ¶é´类åÂÂÃ¥ÂÂ段ï¼Âdatetime
ï¼Â解æÂÂ为 Go è¯Âè¨ÂçÂÂtime.Time
ç±»åÂÂã -
loc=Local
ï¼Â设置æ¶åº为æΡæ¶åºãÂÂè¿Â个åÂÂæ°æÂÂå®Âæ°æ®åºÂ驱å¨ç¨ÂåºÂ使ç¨æΡçÂÂæ¶åºãÂÂ
sql.Open()
è°Âç¨åÂÂå°Âè¿ÂÃ¥ÂÂä¸Â个 *sql.DB
ç±»åÂÂï¼Âå¯以ç¨æÂ¥æÂÂä½Âæ°æ®åºÂãÂÂ
å¦å¤Âï¼ÂæÂÂ们è°Âç¨ defer db.Close()
æÂ¥éÂÂæ¾æ°æ®åºÂè¿ÂæÂ¥ãÂÂÃ¥Â
¶å®Âè¿Âä¸ÂæÂ¥æÂÂä½Âä¹Âå¯以ä¸ÂÃ¥ÂÂï¼Âdatabase/sql
åºÂå±Âè¿Âæ¥池ä¼Â帮æÂÂ们å¤ÂçÂÂãÂÂä¸Âæ¦åÂ
³éÂÂäºÂè¿ÂæÂ¥ï¼Âå°±ä¸Âå¯以åÂÂ继ç»Â使ç¨è¿Â个 db
对象äºÂãÂÂ
*sql.DB
çÂÂ设计æ¯ç¨æÂ¥ä½Â为é¿è¿Âæ¥使ç¨çÂÂï¼ÂæÂÂ以ä¸ÂéÂÂè¦Âé¢Âç¹ÂçÂÂè¿Âè¡ Open
å Close
æÂÂä½ÂãÂÂå¦ÂæÂÂæÂÂ们éÂÂè¦Âè¿ÂæÂ¥å¤Â个æ°æ®åºÂï¼ÂÃ¥ÂÂå¯以为æ¯Â个ä¸ÂÃ¥ÂÂçÂÂæ°æ®åºÂÃ¥ÂÂ建ä¸Â个 *sql.DB
对象ï¼Âä¿ÂæÂÂè¿ÂäºÂ对象为 Open
ç¶æÂÂï¼Âä¸Âå¿Â
é¢Âç¹Â使ç¨ Close
æÂ¥åÂÂæ¢è¿ÂæÂ¥ãÂÂ
å¼å¾Â注æÂÂçÂÂæ¯ï¼ÂÃ¥Â
¶å® sql.Open()
并没æÂÂçÂÂæ£建ç«Âæ°æ®åºÂè¿ÂæÂ¥ï¼Âå®Âåªæ¯åÂÂå¤Â好äºÂä¸ÂÃ¥ÂÂï¼Â以å¤ÂÃ¥ÂÂç»Â使ç¨ï¼Âè¿ÂæÂ¥å°Âå¨第ä¸Â次被使ç¨æ¶延è¿Â建ç«ÂãÂÂ
è¿Âæ ·çÂÂ设计è½ç¶åÂÂçÂÂï¼Âå¯ä¹ÂæÂÂäºÂè¿ÂÃ¥ÂÂç´è§Âï¼Âsql.Open()
çÂÂè³ä¸Âä¼Â校骠DSN Ã¥ÂÂæ°çÂÂÃ¥ÂÂæ³Âæ§ãÂÂä¸Âè¿ÂæÂÂ们å¯以使ç¨ db.Ping()
æ¹æ³Âæ¥主å¨æ£ÂæÂ¥è¿ÂæÂ¥æ¯å¦è½被æ£确建ç«ÂãÂÂ
if err := db.Ping(); err != nil {
log.Fatal(err)
}
使ç¨ sql.Open()
并ä¸Âä¼Â建ç«Âä¸Â个å¯ä¸ÂçÂÂæ°æ®åºÂè¿ÂæÂ¥ï¼ÂäºÂå®Âä¸Âï¼Âdatabase/sql
ä¼Âç»´æ¤ä¸Â个è¿Âæ¥池ãÂÂ
æÂÂ们å¯以éÂÂè¿Âå¦Âä¸Âæ¹æ³Âï¼Âæ§å¶è¿Âæ¥池çÂÂä¸ÂäºÂÃ¥ÂÂæ°ï¼Â
db.SetMaxOpenConns(25) // 设置æÂÂ大çÂÂ并åÂÂè¿ÂæÂ¥æ°ï¼Âin-use + idleï¼Â
db.SetMaxIdleConns(25) // 设置æÂÂ大çÂÂ空é²è¿ÂæÂ¥æ°ï¼Âidleï¼Â
db.SetConnMaxLifetime(5 * time.Minute) // 设置è¿ÂæÂ¥çÂÂæÂÂ大çÂÂå½å¨æÂÂ
è¿ÂäºÂÃ¥ÂÂæ°设置å¯以根æ®ç»ÂéªÂæ¥修æ¹ï¼Â以ä¸ÂÃ¥ÂÂæ°è½å¤Â满足ä¸ÂäºÂä¸Âå°Â项ç®çÂÂ使ç¨ï¼Âå¦ÂæÂÂæ¯大åÂÂ项ç®ï¼ÂÃ¥ÂÂå¯以éÂÂå½Âè°Âé«ÂÃ¥ÂÂæ°ãÂÂ
声æÂÂ模åÂÂ
è¿Âæ¥建ç«Â好åÂÂï¼ÂçÂÂ论ä¸ÂæÂÂ们就å¯以æÂÂä½Âæ°æ®åºÂè¿Âè¡ CRUD äºÂãÂÂä¸Âè¿Â为äºÂÃ¥ÂÂåºçÂÂ代ç Âæ´åÂ
·å¯维æ¤æ§ï¼ÂæÂÂ们å¾Âå¾ÂéÂÂè¦Âå®Âä¹Â模åÂÂ
æÂ¥æ å°Âæ°æ®åºÂ表ãÂÂ
user
表æ å°ÂÃ¥ÂÂçÂÂ模åÂÂå¦Âä¸Âï¼Â
type User struct {
ID int
Name sql.NullString
Email string
Age int
Birthday *time.Time
Salary Salary
CreatedAt time.Time
UpdatedAt string
}
模åÂÂå¨ Go ä¸Â使ç¨ struct
表示ï¼Âç»ÂæÂÂä½ÂÃ¥ÂÂ段åÂÂæ°æ®åºÂ表ä¸ÂçÂÂÃ¥ÂÂ段ä¸Âä¸Â对åºÂãÂÂ
Ã¥Â
¶ä¸ Salary
ç±»åÂÂå®Âä¹Âå¦Âä¸Âï¼Â
type Salary struct {
Month int `json:"month"`
Year int `json:"year"`
}
Ã¥Â
³äº Name
ãÂÂSalary
两个åÂÂ段çÂÂç¹æ®Âæ§ï¼ÂæÂÂå°ÂÃ¥ÂÂå«å¨ å¤Âç NULL å èªå®Âä¹ÂÃ¥ÂÂ段类å é¨åÂÂ讲解ãÂÂ
Ã¥ÂÂ建
*sql.DB
æÂÂä¾Â亠Exec
æ¹æ³ÂæÂ¥æ§è¡Âä¸Âæ¡ SQL å½令ï¼Âå¯以ç¨æÂ¥åÂÂ建ãÂÂæ´æ°ãÂÂå é¤表æ°æ®çÂÂãÂÂ
è¿ÂéÂÂ使ç¨ Exec
æ¹æ³ÂæÂ¥å®Âç°åÂÂ建ä¸Â个ç¨æ·ï¼Â
func CreateUser(db *sql.DB) (int64, error) {
birthday := time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local)
user := User{
Name: sql.NullString{String: "jianghushinian007", Valid: true},
Email: "jianghushinian007@outlook.com",
Age: 10,
Birthday: &birthday,
Salary: Salary{
Month: 100000,
Year: 10000000,
},
}
res, err := db.Exec(`INSERT INTO user(name, email, age, birthday, salary) VALUES(?, ?, ?, ?, ?)`,
user.Name, user.Email, user.Age, user.Birthday, user.Salary)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
é¦ÂÃ¥Â
ÂæÂÂ们å®Âä¾ÂÃ¥ÂÂäºÂä¸Â个 User
对象 user
ï¼Â并对ç¸åºÂÃ¥ÂÂ段è¿Âè¡ÂèµÂå¼ãÂÂ
æÂ¥çÂÂ使ç¨ db.Exec
æ¹æ³ÂæÂ¥æ§衠SQL è¯Âå¥ï¼Â
INSERT INTO user(name, email, age, birthday, salary) VALUES(?, ?, ?, ?, ?)
Ã¥Â
¶ä¸ ?
ä½Â为åÂÂæ°å ä½Â符ï¼Âä¸ÂÃ¥ÂÂæ°æ®åºÂ驱å¨ç¨ÂåºÂçÂÂå ä½Â符å¯è½ä¸ÂÃ¥ÂÂï¼Âå¯以åÂÂèÂÂæ°æ®åºÂ驱å¨çÂÂæÂÂæ¡£ãÂÂ
æÂÂ们å°Âè¿ 5 个åÂÂæ°顺åºÂä¼ éÂÂç» db.Exec
æ¹æ³Âï¼Âå³å¯å®ÂæÂÂç¨æ·çÂÂÃ¥ÂÂ建ãÂÂ
db.Exec
æ¹æ³Âè°Âç¨åÂÂå°Âè¿Âå sql.Result
ä¿ÂÃ¥ÂÂç»ÂæÂÂ以åÂÂä¸Â个 error
æÂ¥æ Âè®°éÂÂ误ãÂÂ
sql.Result
æ¯ä¸Â个æÂ¥å£ï¼Âå®ÂÃ¥ÂÂ
å«两个æ¹æ³Âï¼Â
-
LastInsertId() (int64, error)
ï¼Âè¿ÂÃ¥ÂÂæ°æÂÂå ¥çÂÂç¨æ· IDã -
RowsAffected() (int64, error)
ï¼Âè¿ÂÃ¥ÂÂå½ÂÃ¥ÂÂæÂÂä½ÂÃ¥ÂÂå½±åÂÂçÂÂè¡Âæ°ãÂÂ
æÂ¥å£堷ä½Âå®Âç°æÂÂæ°æ®åºÂ驱å¨ç¨ÂåºÂæÂ¥å®ÂæÂÂãÂÂ
è°Âç¨ CreateUser
å½æ°å³å¯åÂÂ建ä¸Â个æ°çÂÂç¨æ·ï¼Â
if id, err := CreateUser(db); err != nil {
log.Fatal(err)
} else {
log.Println("id:", id)
}
æ¤å¤Âï¼Âdatabase/sql
è¿ÂæÂÂä¾ÂäºÂé¢Âå¤ÂçÂÂæ¹泠*sql.DB.Prepare
Ã¥ÂÂ建ä¸Â个åÂÂå¤Â好ç SQL è¯Âå¥ï¼Âå¨循ç¯ä¸Â使ç¨é¢Âå¤ÂçÂÂï¼ÂÃ¥ÂÂå¯以åÂÂå°Âä¸Âæ°æ®åºÂçÂÂ交äºÂ次æ°ãÂÂ
æ¯Âå¦ÂæÂÂ们éÂÂè¦ÂÃ¥ÂÂ建两个ç¨æ·ï¼ÂÃ¥ÂÂå¯以åÂ
Â使ç¨ db.Prepare
Ã¥ÂÂ建ä¸Â个 *sql.Stmt
对象ï¼Âç¶åÂÂå¤Â次è°Âç¨ *sql.Stmt.Exec
æ¹æ³ÂæÂ¥æÂÂÃ¥Â
¥æ°æ®ï¼Â
func CreateUsers(db *sql.DB) ([]int64, error) {
stmt, err := db.Prepare("INSERT INTO user(name, email, age, birthday, salary) VALUES(?, ?, ?, ?, ?)")
if err != nil {
panic(err)
}
// 注æÂÂï¼Âé¢Âå¤ÂçÂÂ对象æ¯éÂÂè¦ÂÃ¥Â
³éÂÂçÂÂ
defer stmt.Close()
birthday := time.Date(2000, 2, 2, 0, 0, 0, 0, time.Local)
users := []User{
{
Name: sql.NullString{String: "", Valid: true},
Email: "jianghushinian007@gmail.com",
Age: 20,
Birthday: &birthday,
Salary: Salary{
Month: 200000,
Year: 20000000,
},
},
{
Name: sql.NullString{String: "", Valid: false},
Email: "jianghushinian007@163.com",
Age: 30,
},
}
var ids []int64
for _, user := range users {
res, err := stmt.Exec(user.Name, user.Email, user.Age, user.Birthday, user.Salary)
if err != nil {
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
return nil, err
}
ids = append(ids, id)
}
return ids, nil
}
db.Prepare
æ¯é¢ÂÃ¥Â
Âå°Âä¸Â个æ°æ®åºÂè¿ÂæÂ¥åÂÂä¸Â个æ¡ SQL è¯Âå¥ç»Âå®Â并è¿Âå *sql.Stmt
ç»ÂæÂÂä½Âï¼Âå®Â代表äºÂè¿Â个ç»Âå®ÂÃ¥ÂÂçÂÂè¿Âæ¥对象ï¼Âæ¯并åÂÂå®ÂÃ¥Â
¨çÂÂãÂÂ
éÂÂè¿Â使ç¨é¢Âå¤ÂçÂÂï¼Âå¯以é¿å Âå¨循ç¯ä¸Âæ§è¡Âå¤Â次å®Âæ´ç SQL è¯Âå¥ï¼Âä»ÂèÂÂæ¾èÂÂÃ¥ÂÂå°ÂäºÂæ°æ®åºÂ交äºÂ次æ°ï¼Âè¿Âå¯以æÂÂé«ÂåºÂç¨ç¨ÂåºÂçÂÂæ§è½åÂÂæÂÂçÂÂãÂÂ
使ç¨é¢Âå¤ÂçÂÂï¼Âä¼Âå¨ db.Prepare
æ¶ä»Âè¿Âæ¥池è·åÂÂä¸Â个è¿ÂæÂ¥ï¼Âä¹ÂÃ¥ÂÂ循ç¯æ§衠stmt.Exec
ï¼ÂæÂÂç»ÂéÂÂæ¾è¿ÂæÂ¥ãÂÂ
å¦ÂæÂÂ使ç¨ db.Exec
ï¼ÂÃ¥ÂÂæ¯Â次循ç¯æ¶é½éÂÂè¦Âï¼Âè·åÂÂè¿ÂæÂÂ¥-æ§衠SQL-éÂÂæ¾è¿ÂæÂ¥ï¼Âè¿Âå 个æ¥骤ï¼Â大大å¢Âå äºÂä¸Âæ°æ®åºÂçÂÂ交äºÂ次æ°ãÂÂ
ä¸Âè¦Âå¿Âè®°è°Âç¨ stmt.Close()
Ã¥Â
³éÂÂè¿ÂæÂ¥ï¼Âè¿Â个æ¹æ³Âæ¯å¯ÂçÂÂçÂÂï¼Âå¯以å¤Â次è°Âç¨ãÂÂ
æ¥询
ç°å¨æ°æ®åºÂéÂÂå·²ç»ÂæÂÂäºÂæ°æ®ï¼ÂæÂÂ们就å¯以æ¥询æ°æ®äºÂãÂÂ
å 为 Exec
æ¹æ³Âåªä¼Âæ§衠SQLï¼Âä¸Âä¼Âè¿ÂÃ¥ÂÂç»ÂæÂÂï¼ÂæÂÂ以ä¸ÂéÂÂç¨äºÂæ¥询æ°æ®ãÂÂ
*sql.DB
æÂÂä¾Â亠Query
æ¹æ³Âæ§è¡Âæ¥询æÂÂä½Âï¼Â
func GetUsers(db *sql.DB) ([]User, error) {
rows, err := db.Query("SELECT * FROM user;")
if err != nil {
return nil, err
}
defer func() { _ = rows.Close() }()
var users []User
for rows.Next() {
var user User
if err := rows.Scan(&user.ID, &user.Name, &user.Email, &user.Age,
&user.Birthday, &user.Salary, &user.CreatedAt, &user.UpdatedAt); err != nil {
log.Println(err.Error())
continue
}
users = append(users, user)
}
// å¤ÂçÂÂéÂÂ误
if err := rows.Err(); err != nil {
return nil, err
}
return users, nil
}
db.Query
è¿ÂÃ¥ÂÂæ¥询ç»ÂæÂÂé *sql.Rows
ï¼Âè¿Âæ¯ä¸Â个ç»ÂæÂÂä½ÂãÂÂ
rows.Next()
æ¹æ³Âç¨æÂ¥å¤æÂÂæ¯å¦è¿ÂæÂÂä¸Âä¸Âæ¡ç»ÂæÂÂï¼Âå¯以ç¨亠for
循ç¯ï¼Âé¢Âå¤Âè¯Âï¼Âè¿ÂæÂÂç¹å Python çÂÂè¿Â代å¨ï¼Âåªä¸Âè¿Âä¸Âä¸Â个å¼ä¸Âæ¯ç´æÂ¥è¿ÂÃ¥ÂÂï¼ÂèÂÂæ¯éÂÂè¿ Scan
æ¹æ³Âè·åÂÂï¼ÂãÂÂ
å¦ÂæÂÂÃ¥ÂÂå¨ä¸Âä¸Âæ¡ç»ÂæÂÂï¼Ârows.Next()
å°Âè¿Âå true
ãÂÂ
rows.Scan()
æ¹æ³Âå¯以å°Âç»ÂæÂÂæ«æÂÂå°传éÂÂè¿ÂæÂ¥çÂÂæÂÂéÂÂ对象ãÂÂå 为æÂÂ们使ç¨亠SELECT *
æÂ¥æ¥询ï¼ÂæÂÂ以ä¼Âè¿ÂÃ¥ÂÂÃ¥Â
¨é¨åÂÂ段çÂÂæ°æ®ï¼ÂæÂÂ顺åºÂå° user
对象ç¸åºÂçÂÂÃ¥ÂÂ段æÂÂéÂÂä¼ éÂÂè¿ÂæÂ¥å³å¯ãÂÂ
rows.Scan()
ä¼Âå°Âä¸Âè¡Âè®°å½ÂÃ¥ÂÂå«填åÂ
¥æÂÂå®ÂçÂÂÃ¥ÂÂéÂÂä¸Âï¼Â并ä¸Âä¼Âèªå¨根æ®ç®æ ÂÃ¥ÂÂéÂÂçÂÂç±»åÂÂå¤ÂçÂÂç±»åÂÂ转æ¢çÂÂé®é¢Âï¼Âæ¯Âå¦Âæ°æ®åºÂä¸Âæ¯ varchar
ç±»åÂÂï¼Âä¼Âæ å°Âæ Go ä¸Âç string
ï¼Âä½Âå¦ÂæÂÂä¸Âä¹Â对åºÂçÂÂç®æ ÂÃ¥ÂÂéÂÂæ¯ int
ï¼Âé£ä¹Â转æ¢失败就ä¼Âè¿Âå error
ãÂÂ
CreatedAt
Ã¥ÂÂ段æ¯ time.Time
ç±»åÂÂï¼Âä¹ÂæÂÂ以è½å¤Â被æ£确å¤ÂçÂÂï¼Âæ¯å 为å¨è°Âç¨ sql.Open()
æ¶传éÂÂç DSN Ã¥ÂÂ
å« parseTime=true
Ã¥ÂÂæ°ãÂÂ
å½ rows.Next()
è¿ÂÃ¥ÂÂ为 false
æ¶ï¼Âå³ä¸ÂÃ¥ÂÂæÂÂä¸Âä¸Âæ¡记å½ÂãÂÂæÂÂ们ä¹Âå°±å°ÂÃ¥Â
¨é¨æ¥询åºæÂ¥çÂÂç¨æ·é½åÂÂå¨å° users
Ã¥ÂÂçÂÂä¸ÂäºÂãÂÂ
循ç¯ç»ÂæÂÂÃ¥ÂÂï¼ÂÃ¥ÂÂè®°ä¸Âå®Âè¦Âè°Âç¨ rows.Err()
æÂ¥å¤ÂçÂÂéÂÂ误ãÂÂ
以ä¸Âï¼ÂæÂÂ们æ¥询äºÂå¤Âæ¡ç¨æ·ï¼Â*sql.DB
è¿ÂæÂÂä¾Â亠QueryRow
æ¹æ³Âå¯以æ¥询åÂÂæ¡记å½Âï¼Â
func GetUser(db *sql.DB, id int64) (User, error) {
var user User
row := db.QueryRow("SELECT * FROM user WHERE id = ?", id)
err := row.Scan(&user.ID, &user.Name, &user.Email, &user.Age,
&user.Birthday, &user.Salary, &user.CreatedAt, &user.UpdatedAt)
switch {
case err == sql.ErrNoRows:
return user, fmt.Errorf("no user with id %d", id)
case err != nil:
return user, err
}
// å¤ÂçÂÂéÂÂ误
if err := row.Err(); err != nil {
return user, err
}
return user, nil
}
æ¥询åÂÂæ¡记å½Âä¼Âè¿Âå *sql.Row
ç»ÂæÂÂä½Âï¼Âå®Âå®ÂéÂÂ
ä¸Âæ¯对 *sql.Rows
çÂÂä¸Âå±ÂÃ¥ÂÂ
è£Â
ï¼Â
type Row struct {
// One of these two will be non-nil:
err error // deferred error for easy chaining
rows *Rows
}
æÂÂ们ä¸ÂÃ¥ÂÂéÂÂè¦Âè°Âç¨ rows.Next()
å¤æÂÂæ¯å¦æÂÂä¸Âä¸Âæ¡ç»ÂæÂÂï¼Âè°Âç¨ row.Sca()
æ¶ *sql.Row
ä¼Âèªå¨帮æÂÂ们å¤ÂçÂÂ好ï¼Âè¿ÂÃ¥ÂÂæ¥询ç»ÂæÂÂéÂÂä¸ÂçÂÂ第ä¸Âæ¡æ°æ®ãÂÂ
å¦Âæ row.Sca()
è¿ÂÃ¥ÂÂçÂÂéÂÂ误类åÂÂ为 sql.ErrNoRows
说æÂÂ没æÂÂæ¥询å°符åÂÂæ¡件çÂÂæ°æ®ï¼Âè¿Â对äºÂå¤æÂÂéÂÂ误类åÂÂç¹å«æÂÂç¨ãÂÂ
ä½ database/sql
æ¾ç¶ä¸Âè½æÂÂ举åºæÂÂæÂÂæ°æ®åºÂçÂÂéÂÂ误类åÂÂï¼ÂæÂÂäºÂéÂÂ对ä¸ÂÃ¥ÂÂæ°æ®åºÂçÂÂæÂÂå®ÂéÂÂ误类åÂÂï¼ÂéÂÂ常ç±æ°æ®åºÂ驱å¨ç¨ÂåºÂæÂ¥å®Âä¹ÂãÂÂ
å¯以æÂÂç §å¦Âä¸Âæ¹å¼Âå¤æÂÂç¹å®Âç MySQL éÂÂ误类åÂÂï¼Â
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number == 1045 {
// å¤ÂçÂÂ被æÂÂç»ÂçÂÂéÂÂ误
}
}
ä¸Âè¿Âå 1045
è¿Âç§ÂéÂÂæ³Âæ°åÂÂæÂÂ好ä¸Âè¦Âåºç°å¨代ç Âä¸Âï¼Âmysqlerr Ã¥ÂÂ
æÂÂä¾Â亠MySQL éÂÂ误类åÂÂçÂÂæÂÂ举ãÂÂ
以ä¸Â代ç Âå¯以æ¹为ï¼Â
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number == mysqlerr.ER_ACCESS_DENIED_ERROR {
// å¤ÂçÂÂ被æÂÂç»ÂçÂÂéÂÂ误
}
}
æÂÂÃ¥ÂÂï¼ÂÃ¥ÂÂæ ·ä¸Âè¦Âå¿Âè®°è°Âç¨ row.Err()
å¤ÂçÂÂéÂÂ误ãÂÂ
æ´æ°
æ´æ°æÂÂä½ÂÃ¥ÂÂÃ¥ÂÂ建ä¸Âæ ·å¯以使ç¨ *sql.DB.Exec
æ¹æ³ÂæÂ¥å®Âç°ï¼Âä¸Âè¿Âè¿ÂéÂÂæÂÂ们å°Â使ç¨ *sql.DB.ExecContext
æ¹æ³ÂæÂ¥å®Âç°ãÂÂ
ExecContext
æ¹æ³Â丠Exec
æ¹æ³Âå¨使ç¨ä¸Â没ä»Âä¹Â两样ï¼Âåªä¸Âè¿Â第ä¸Â个åÂÂæ°éÂÂè¦ÂæÂ¥æ¶ä¸Â个 context.Context
ï¼Âå®ÂÃ¥Â
Â许你æ§å¶åÂÂÃ¥ÂÂæ¶Âæ§衠SQL è¯Âå¥çÂÂæÂÂä½ÂãÂÂ使ç¨ä¸Âä¸ÂæÂÂå¯以å¨éÂÂè¦ÂçÂÂæÂÂ
åµä¸Â设置è¶Â
æ¶æ¶é´ãÂÂå¤ÂçÂÂ请æ±ÂÃ¥ÂÂæ¶ÂçÂÂæÂÂä½ÂãÂÂ
func UpdateUserName(db *sql.DB, id int64, name string) error {
ctx := context.Background()
res, err := db.ExecContext(ctx, "UPDATE user SET name = ? WHERE id = ?", name, id)
if err != nil {
return err
}
affected, err := res.RowsAffected()
if err != nil {
return err
}
if affected == 0 {
// å¦ÂæÂÂæ°ç name çÂÂäºÂå nameï¼Âä¹Âä¼Âæ§è¡Âå°è¿ÂéÂÂ
return fmt.Errorf("no user with id %d", id)
}
return nil
}
è¿ÂéÂÂ使ç¨ res.RowsAffected()
è·åÂÂäºÂå½ÂÃ¥ÂÂæÂÂä½Âå½±åÂÂçÂÂè¡Âæ°ãÂÂ
注æÂÂï¼Âå¦ÂæÂÂæ´æ°åÂÂçÂÂÃ¥ÂÂ段ç»ÂæÂÂ没æÂÂÃ¥ÂÂÃ¥ÂÂï¼Âres.RowsAffected()
è¿Âå 0ãÂÂ
å é¤
使ç¨ *sql.DB.ExecContext
æ¹æ³Âå®Âç°å é¤ç¨æ·ï¼Â
func DeleteUser(db *sql.DB, id int64) error {
ctx := context.Background()
res, err := db.ExecContext(ctx, "DELETE FROM user WHERE id = ?", id)
if err != nil {
return err
}
affected, err := res.RowsAffected()
if err != nil {
return err
}
if affected == 0 {
return fmt.Errorf("no user with id %d", id)
}
return nil
}
äºÂå¡
äºÂå¡åºæ¾¯å¼Âå Web 项ç®æ¶æ¯Âä¸Âå¯å°ÂçÂÂæ°æ®åºÂÃ¥ÂÂè½ï¼Âdatabase/sql
æÂÂä¾ÂäºÂ对äºÂå¡çÂÂæ¯æÂÂãÂÂ
å¦Âä¸Â示ä¾Â使ç¨äºÂå¡æÂ¥æ´æ°ç¨æ·ï¼Â
func Transaction(db *sql.DB, id int64, name string) error {
ctx := context.Background()
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
if err != nil {
return err
}
_, execErr := tx.ExecContext(ctx, "UPDATE user SET name = ? WHERE id = ?", name, id)
if execErr != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("update failed: %v, unable to rollback: %v\n", execErr, rollbackErr)
}
log.Fatalf("update failed: %v", execErr)
}
return tx.Commit()
}
*sql.DB.BeginTx
ç¨äºÂå¼Âå¯ä¸Â个äºÂå¡ï¼Â第ä¸Â个åÂÂæ°为 context.Context
ï¼Â第äºÂ个åÂÂæ°为 *sql.TxOptions
对象ï¼Âç¨æÂ¥éÂ
Âç½®äºÂå¡éÂÂ项ï¼ÂIsolation
Ã¥ÂÂ段ç¨æ¥设置æ°æ®åºÂéÂÂ离级å«ï¼ÂÃ¥Â
³äºÂéÂÂ离级å«å«ä¹Âå¯以åÂÂèÂÂè¿ÂéÂÂãÂÂ
äºÂå¡ä¸Âæ§è¡Âç SQL è¯Âå¥éÂÂè¦Âæ¾å¨ tx
对象ç ExecContext
æ¹æ³Âä¸Âæ§è¡Âï¼ÂèÂÂä¸Âæ¯ db.ExecContext
ãÂÂ
å¦ÂæÂÂæ§衠SQL è¿Âç¨Âä¸Âåºç°éÂÂ误ï¼Âå¯以使ç¨ tx.Rollback()
è¿Âè¡ÂäºÂå¡åÂÂæ»ÂãÂÂ
å¦ÂæÂÂ没æÂÂéÂÂ误ï¼ÂÃ¥ÂÂå¯以使ç¨ tx.Commit()
æÂÂ交äºÂå¡ãÂÂ
tx
Ã¥ÂÂæ ·æ¯æ Prepare
æ¹æ³Âï¼Âå¯以ç¹å»è¿ÂéÂÂæÂ¥çÂÂ使ç¨示ä¾ÂãÂÂ
å¤Âç NULL
å¨åÂÂ建 User
模åÂÂæ¶ï¼ÂæÂÂ们å®Âä¹ Name
Ã¥ÂÂ段类åÂÂ为 sql.NullString
ï¼ÂèÂÂéÂÂæ®éÂÂç string
ç±»åÂÂï¼Âè¿Âæ¯为äºÂæ¯æÂÂæ°æ®åºÂä¸Âç NULL
ç±»åÂÂãÂÂ
æ°æ®åºÂ丠name
Ã¥ÂÂ段å®Âä¹Âå¦Âä¸Âï¼Â
`name` varchar(50) DEFAULT NULL COMMENT 'ç¨æ·åÂÂ'
é£习name
å¨æ°æ®åºÂä¸Âå¯è½çÂÂå¼å°ÂæÂÂä¸Âç§ÂæÂÂ
Ã¥Â括ÂNULL
ãÂÂ空åÂÂ符串 ''
以åÂÂæÂÂå¼çÂÂÃ¥ÂÂ符串 'n1'
ãÂÂ
æÂÂ们çÂ¥éÂÂï¼ÂGo è¯Âè¨Â丠string
ç±»åÂÂçÂÂé»Â认å¼å³为空åÂÂ符串 ''
ï¼Âä½Âæ¯ string
æ æ³Â表示 NULL
å¼ãÂÂ
è¿Â个æ¶åÂÂï¼ÂæÂÂ们æÂÂ两ç§Âæ¹æ³Â解å³æ¤é®é¢Âï¼Â
-
使ç¨æÂÂéÂÂç±»åÂÂãÂÂ
-
使ç¨
sql.NullString
ç±»åÂÂãÂÂ
å 为æÂÂéÂÂç±»åÂÂå¯è½为 nil
ï¼ÂæÂÂ以å¯以使ç¨ nil
æ¥对庠NULL
å¼ãÂÂè¿Âå°±æ¯ User
模åÂÂ丠Birthday
Ã¥ÂÂ段类åÂÂå®Âä¹Â为 *time.Time
çÂÂç¼ÂæÂÂ
ãÂÂ
sql.NullString
ç±»åÂÂå®Âä¹Âå¦Âä¸Âï¼Â
type NullString struct {
String string
Valid bool // Valid is true if String is not NULL
}
String
ç¨æ¥记å½Âå¼ï¼ÂValid
ç¨æÂ¥æ Âè®°æ¯å¦为 NULL
ãÂÂ
NullString
ç»ÂæÂÂä½ÂçÂÂå¼åÂÂæ°æ®åºÂä¸Âå®ÂéÂÂ
Ã¥ÂÂå¨çÂÂå¼ï¼ÂæÂÂå¦Âä¸Âæ å°ÂÃ¥Â
³ç³»ï¼Â
value | value for MySQL |
---|---|
{String:n1 Valid:true} |
'n1' |
{String: Valid:true} |
'' |
{String: Valid:false} |
NULL |
æ¤å¤Âï¼Âsql.NullString
ç±»åÂÂè¿Âå®Âç°亠sql.Scanner
å driver.Valuer
两个æÂ¥å£ï¼Â
// Scan implements the Scanner interface.
func (ns *NullString) Scan(value any) error {
if value == nil {
ns.String, ns.Valid = "", false
return nil
}
ns.Valid = true
return convertAssign(&ns.String, value)
}
// Value implements the driver Valuer interface.
func (ns NullString) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return ns.String, nil
}
è¿Â两个æÂ¥å£åÂÂå«ç¨å¨ *sql.Row.Scan
æ¹æ³Âå *sql.DB.Exec
æ¹æ³ÂãÂÂ
å³å¨使ç¨ *sql.DB.Exec
æ¹æ³Âæ§衠SQL æ¶ï¼ÂæÂÂ们å¯è½éÂÂè¦Âå° Name
Ã¥ÂÂ段çÂÂå¼åÂÂÃ¥Â
Â¥ MySQLï¼Âæ¤æ¶ database/sql
ä¼Âè°Âç¨ sql.NullString
ç±»åÂÂç Value()
æ¹æ³Âï¼Âè·åÂÂÃ¥Â
¶å°Âè¦ÂÃ¥ÂÂå¨äºÂæ°æ®åºÂä¸ÂçÂÂå¼ãÂÂ
å¨使ç¨ *sql.Row.Scan
æ¹æ³Âæ¶ï¼ÂæÂÂ们å¯è½éÂÂè¦Âå°Âä»Âæ°æ®åºÂè·åÂÂå°ç name
Ã¥ÂÂ段å¼æ å°Âå° User
ç»ÂæÂÂä½ÂÃ¥ÂÂ段 Name
ä¸Âï¼Âæ¤æ¶ database/sql
ä¼Âè°Âç¨ sql.NullString
ç±»åÂÂç Scan()
æ¹æ³Âï¼ÂæÂÂä»Âæ°æ®åºÂä¸Âæ¥询çÂÂå¼èµÂå¼绠Name
Ã¥ÂÂ段ãÂÂ
å¦ÂæÂÂ你使ç¨çÂÂÃ¥ÂÂ段ä¸Âæ¯ string
ç±»åÂÂï¼Âdatabase/sql
è¿ÂæÂÂä¾Â亠sql.NullBool
ãÂÂsql.NullFloat64
çÂÂç±»åÂÂä¾Âç¨æ·使ç¨ãÂÂ
ä½Âæ¯ï¼Âè¿Â并ä¸Âè½æÂÂ举åºæÂÂæ MySQL æ°æ®åºÂæ¯æÂÂçÂÂÃ¥ÂÂ段类åÂÂï¼ÂæÂÂ以å¦ÂæÂÂè½å¤Âå°½éÂÂé¿åÂ
Âï¼Âè¿Âæ¯ä¸Â建议æ°æ®åºÂÃ¥ÂÂ段åÂ
Â许 NULL
å¼ãÂÂ
èªå®Âä¹ÂÃ¥ÂÂ段类åÂÂ
æÂÂäºÂæ¶åÂÂï¼ÂæÂÂ们ä¿ÂÃ¥ÂÂå¨æ°æ®åºÂä¸ÂçÂÂæ°æ®æÂÂçÂÂç¹å®ÂçÂÂæ ¼å¼Âï¼Âæ¯Â妠salary
Ã¥ÂÂ段å¨æ°æ®åºÂä¸ÂÃ¥ÂÂå¨çÂÂå¼为 {"month":100000,"year":10000000}
ãÂÂ
æ°æ®åºÂ丠salary
Ã¥ÂÂ段å®Âä¹Âå¦Âä¸Âï¼Â
`salary` varchar(128) DEFAULT NULL COMMENT 'èª水'
å¦ÂæÂÂåªæ¯å°ÂÃ¥Â
¶æ å°Â为 Go ä¸Âç string
ï¼ÂÃ¥ÂÂæÂÂä½Âæ¶è¦Âæ ¼å¤Âå°Âå¿Âï¼Âå¦ÂæÂÂå¿Âè®°åÂÂä¸Â个 "
æ ,
çÂÂï¼Âç¨ÂåºÂå°Âå¯è½æÂ¥éÂÂãÂÂ
å 为 salary
å¼æÂÂæ¾æ¯ä¸Â个 JSON æ ¼å¼Âï¼ÂæÂÂ们å¯以å®Âä¹Âä¸Â个 struct
æÂ¥æ å°ÂÃ¥Â
¶åÂÂ
容ï¼Â
type Salary struct {
Month int `json:"month"`
Year int `json:"year"`
}
è¿Âè¿Âä¸Âå¤Âï¼Âèªå®Âä¹Âç±»åÂÂæ æ³Âæ¯æ *sql.Row.Scan
æ¹æ³Âå *sql.DB.Exec
æ¹æ³ÂãÂÂ
ä¸Âè¿Âï¼ÂæÂÂæ³你已ç»ÂçÂÂå°äºÂï¼ÂæÂÂ们å¯以åÂÂè sql.NullString
ç±»åÂÂ让 Salary
Ã¥ÂÂæ ·å®Âç° sql.Scanner
å driver.Valuer
两个æÂ¥å£ï¼Â
// Scan implements sql.Scanner
func (s *Salary) Scan(src any) error {
if src == nil {
return nil
}
var buf []byte
switch v := src.(type) {
case []byte:
buf = v
case string:
buf = []byte(v)
default:
return fmt.Errorf("invalid type: %T", src)
}
err := json.Unmarshal(buf, s)
return err
}
// Value implements driver.Valuer
func (s Salary) Value() (driver.Value, error) {
v, err := json.Marshal(s)
return string(v), err
}
è¿Âæ ·ï¼ÂÃ¥ÂÂå¨åÂÂæ¥询æ°æ®çÂÂæÂÂä½Âï¼ÂSalary
ç±»åÂÂé½è½å¤Âæ¯æÂÂãÂÂ
æªçÂ¥åÂÂ
æÂÂ端æÂÂ
åµä¸Âï¼ÂæÂÂ们å¯è½ä¸ÂçÂ¥éÂÂ使ç¨ *sql.DB.Query
æ¹æ³Âæ¥询çÂÂç»ÂæÂÂéÂÂä¸Âæ°æ®çÂÂÃ¥ÂÂÃ¥ÂÂ以åÂÂÃ¥ÂÂ段个æ°ãÂÂ
æ¤æ¶ï¼ÂæÂÂ们å¯以使ç¨ *sql.Rows.Columns
æ¹æ³Âè·åÂÂæÂÂæÂÂÃ¥ÂÂÃ¥ÂÂï¼Âè¿Âå°Âè¿ÂÃ¥ÂÂä¸Â个åÂÂçÂÂï¼Âè¿Â个åÂÂçÂÂé¿度ï¼Âå³为åÂÂ段个æ°ãÂÂ
示ä¾Â代ç Âå¦Âä¸Âï¼Â
func HandleUnknownColumns(db *sql.DB, id int64) ([]interface{}, error) {
var res []interface{}
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)
if err != nil {
return res, err
}
defer func() { _ = rows.Close() }()
// å¦ÂæÂÂä¸ÂçÂ¥éÂÂÃ¥ÂÂÃ¥ÂÂ称ï¼Âå¯以使ç¨ rows.Columns() æÂ¥æ¾åÂÂÃ¥ÂÂ称åÂÂ表
cols, err := rows.Columns()
if err != nil {
return res, err
}
fmt.Printf("columns: %v\n", cols) // [id name email age birthday salary created_at updated_at]
fmt.Printf("columns length: %d\n", len(cols))
// è·åÂÂÃ¥ÂÂç±»åÂÂä¿¡æ¯
types, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
for _, typ := range types {
// id: &{name:id hasNullable:true hasLength:false hasPrecisionScale:false nullable:false length:0 databaseType:INT precision:0 scale:0 scanType:0x1045d68a0}
fmt.Printf("%s: %+v\n", typ.Name(), typ)
}
res = []interface{}{
new(int), // id
new(sql.NullString), // name
new(string), // email
new(int), // age
new(time.Time), // birthday
new(Salary), // salary
new(time.Time), // created_at
// å¦ÂæÂÂä¸ÂçÂ¥éÂÂÃ¥ÂÂç±»åÂÂï¼Âå¯以使ç¨ sql.RawBytesï¼Âå®Âå®ÂéÂÂ
ä¸Âæ¯ []byte çÂÂå«åÂÂ
new(sql.RawBytes), // updated_at
}
for rows.Next() {
if err := rows.Scan(res...); err != nil {
return res, err
}
}
return res, rows.Err()
}
é¤äºÂè·åÂÂÃ¥ÂÂÃ¥ÂÂÃ¥ÂÂÃ¥ÂÂ段个æ°ï¼ÂæÂÂ们è¿Âå¯以使ç¨ *sql.Rows.ColumnTypes
æ¹æ³Âè·åÂÂæ¯Â个 column
çÂÂ详ç»Âä¿¡æ¯ãÂÂ
å¦ÂæÂÂæÂÂ们ä¸ÂçÂ¥éÂÂæÂÂ个åÂÂ段å¨æ°æ®åºÂä¸ÂçÂÂç±»åÂÂï¼ÂÃ¥ÂÂå¯以å°ÂÃ¥Â
¶æ å°Â为 sql.RawBytes
ç±»åÂÂï¼Âå®Âå®ÂéÂÂ
ä¸Âæ¯ []byte
çÂÂå«åÂÂãÂÂ
æ»ç»Â
database/sql
Ã¥ÂÂ
ç»Âä¸Â亠Go è¯Âè¨ÂæÂÂä½Âæ°æ®åºÂçÂÂç¼Âç¨ÂæÂ¥å£ï¼Âé¿åÂ
ÂäºÂæÂÂä½Âä¸ÂÃ¥ÂÂæ°æ®åºÂéÂÂè¦Âå¦习å¤Â奠API çÂÂçªÂå¢ÂãÂÂ
使ç¨ sql.Open()
建ç«Âæ°æ®åºÂè¿Âæ¥并ä¸Âä¼Âç«ÂÃ¥ÂȍÂÂæÂÂï¼Âè¿ÂæÂ¥ä¼Âå¨åÂÂéÂÂçÂÂæ¶åÂÂ延è¿Â建ç«ÂãÂÂ
æÂÂ们å¯以使ç¨ *sql.DB.Exec
/ *sql.DB.ExecContext
æÂ¥æ§衠SQL å½令ãÂÂÃ¥Â
¶å®Âé¤亠Exec
æÂÂæ¹æ³Â对åºÂç ExecContext
çÂÂæ¬ï¼ÂæÂÂä¸ÂæÂÂå°ç *sql.DB.Ping
ãÂÂ*sql.DB.Query
ãÂÂ*sql.DB.QueryRow
ãÂÂ*sql.DB.Prepare
æ¹æ³Âä¹Âé½æÂÂ对åºÂç XxxContext
çÂÂæ¬ï¼Âä½ å¯以èªè¡ÂæµÂè¯ÂãÂÂ
å¦ÂæÂÂ被æ§è¡Âç SQL è¯Âå¥ä¸ÂÃ¥ÂÂ
å« MySQL Ã¥Â
³é®åÂÂï¼ÂÃ¥ÂÂéÂÂè¦Â使ç¨åÂÂå¼Âå·ï¼Â`ï¼Âå°ÂÃ¥Â
³é®åÂÂè¿Âè¡ÂÃ¥ÂÂ
裹ï¼Âå¦åÂÂä½ å°Âå¾Âå° Error 1064 (42000): You have an error in your SQL syntax;
éÂÂ误ãÂÂ
*sql.DB.BeginTx
å¯以å¼Âå¯ä¸Â个äºÂå¡ï¼ÂäºÂå¡éÂÂè¦Âæ¾å¼Âç Commit
æ Rollback
ï¼ÂMySQL 驱å¨è¿Âæ¯æÂÂ使ç¨ *sql.TxOptions
设置äºÂå¡éÂÂ离级å«ãÂÂ
对亠NULL
ç±»åÂÂï¼Âdatabase/sql
æÂÂä¾Â亠sql.NullString
çÂÂç±»åÂÂçÂÂæ¯æÂÂãÂÂæÂÂ们ä¹Âå¯以为èªå®Âä¹Âç±»åÂÂå®Âç° sql.Scanner
å driver.Valuer
两个æÂ¥å£ï¼ÂæÂ¥å®Âç°ç¹å®Âé»è¾ÂãÂÂ
对äºÂæªçÂ¥åÂÂÃ¥ÂÂÃ¥ÂÂ段类åÂÂï¼ÂæÂÂ们å¯以使ç¨ *sql.Rows.Columns
ãÂÂsql.RawBytes
çÂÂæ¥解å³ï¼Âè½ç¶è¿ÂæÂÂ大çÂÂå¢Âå äºÂçµ活æ§ï¼Âä¸Âè¿Âä¸Âå°ä¸Âä¸Âå¾Âå·²ä¸Â建议使ç¨ï¼Â使ç¨æ´å æÂÂç¡®çÂÂ代ç Âå¯以åÂÂå° BUG çÂÂæ°éÂÂÃ¥ÂÂæÂÂé«Âå¯维æ¤æ§ãÂÂ
æ¾ÂÂå®Âæ´代ç Â示ä¾ÂæÂÂæ¾å¨亠GitHub ä¸Âï¼Â欢è¿Âç¹åÂȾÂ¥çÂÂãÂÂ
å¸ÂæÂÂæ¤æÂÂè½对你æÂÂæÂÂ帮å©ãÂÂ
èÂÂç³»æÂÂ
- 微信ï¼Âjianghushinian
- é®箱ï¼Âjianghushinian007@outlook.com
- Ã¥ÂÂ客å°åÂÂï¼Âjianghushinian.cn/
Ã¥ÂÂèÂÂ
- database/sql æÂÂæ¡£ï¼Âpkg.go.dev/database/sqâ¦
- SQLDrivers 驱å¨åÂÂ表ï¼Âgithub.com/golang/go/wâ¦
- MySQL Driverï¼Âgithub.com/go-sql-drivâ¦
- Go database/sql tutorialï¼Âgo-database-sql.org/index.html
- Configuring sql.DB for Better Performanceï¼Âwww.alexedwards.net/blog/configâ¦
- æ¾ÂÂ示ä¾Â代ç Âï¼Âgithub.com/jianghushinâ¦