Golang SQL 操作初体验
简介Golang 提供了 database/sql 包用于对 SQL 的数据库的访问,在这个包中,最重要的自然就是 sql.DB 了.
有一点需要注意的是,正因为 sql.DB 是以连接池的方式管理数据库连接,我们每次进行数据库操作时,都需要从连接池中取出一个连接,当操作任务完成时,我们需要将此连接返回到连接池中,因此如果我们没有正确地将连接返回给连接池,那么会造成 db.SQL 打开过多的数据库连接,使数据库连接资源耗尽. MySQL 数据库的基本操作数据库驱动的导入有过数据库开发经验的朋友就知道了,我们需要借助于一个数据库驱动才能和具体的数据库进行连接. 这在 Golang 中也不例外. 例如以 MySQL 数据库为例: import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) 需要注意的是,通常来说,我们不应该直接使用驱动所提供的方法,而是应该使用 sql.DB,因此在导入 mysql 驱动时,我们使用了匿名导入的方式(在包路径前添加 _). 数据库的连接当导入了 MySQL 驱动后,我们打开数据库连接: func main() { db,err := sql.Open("mysql","user:password@tcp(127.0.0.1:3306)/test") if err != nil { log.Fatal(err) } defer db.Close() } 通过 sql.Open 函数,可以创建一个数据库抽象操作接口,如果打开成功的话,它会返回一个 sql.DB 指针. func Open(driverName,dataSourceName string) (*DB,error) 它接收两个参数:
err = db.Ping() if err != nil { log.Fatal(err) }
数据库的查询数据库查询的一般步骤如下:
例如我们有如下一个数据库表: CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(20) DEFAULT '',`age` int(11) DEFAULT '0',PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 我们向其中插入一条记录: func insertData(db *sql.DB) { rows,err := db.Query(`INSERT INTO user (id,name,age) VALUES (1,"xys",20)`) defer rows.Close() if err != nil { log.Fatalf("insert data error: %vn",err) } var result int rows.Scan(&result) log.Printf("insert result %vn",result) } 通过调用 db.Query,我们执行了一条 INSERT 语句插入了一条数据. 当执行完毕后,首先需要做的是检查语句是否执行成功,当没有错误时,就通过 rows.Scan 获取执行的结果. 因为 INSERT 返回的是插入的数据的行数,因此我们打印的语句就是 "insert result 0". 接下来如法炮制,我们从数据库中将插入的数据取出: func selectData(db *sql.DB) { var id int var name string var age int rows,err := db.Query(`SELECT * From user where id = 1`) if err != nil { log.Fatalf("insert data error: %vn",err) return } for rows.Next() { rows.Scan(&id,&age,&name) if err != nil { log.Fatal(err) } log.Printf("get data,id: %d,name: %s,age: %d",id,age) } err = rows.Err() if err != nil { log.Fatal(err) } } 上面的代码的流程基本上没有很大的差别,不过我们需要注意一点的是 rows.Scan 参数的顺序很重要,需要和查询的结果的 column 对应. 例如 "SELECT * From user where id = 1" 查询的行的 column 顺序是 "id,age",因此 rows.Scan 也需要按照此顺序 rows.Scan(&id,&name,&age),不然会造成数据读取的错位.
完整的例子如下: func insertData(db *sql.DB) { rows,20)`) defer rows.Close() if err != nil { log.Fatalf("insert data error: %vn",result) } func selectData(db *sql.DB) { var id int var name string var age int rows,err := db.Query(`SELECT id,age From user where id = 1`) if err != nil { log.Fatalf("insert data error: %vn",err) return } for rows.Next() { err = rows.Scan(&id,&age) if err != nil { log.Fatal(err) } log.Printf("get data,age) } err = rows.Err() if err != nil { log.Fatal(err) } } func main() { db,"root:root@tcp(127.0.0.1:3306)/test") defer db.Close() if err != nil { fmt.Printf("connect to db 127.0.0.1:3306 error: %vn",err) return } insertData(db) selectData(db) } 预编译语句(Prepared Statement)预编译语句(PreparedStatement)提供了诸多好处,因此我们在开发中尽量使用它. 下面列出了使用预编译语句所提供的功能:
下面我们将上一小节的例子使用 Prepared Statement 来改写: func deleteData(db *sql.DB) { stmt,_ := db.Prepare(`DELETE FROM user WHERE id = ?`) rows,err := stmt.Query(1) defer stmt.Close() rows.Close() if err != nil { log.Fatalf("delete data error: %vn",err) } rows,err = stmt.Query(2) rows.Close() if err != nil { log.Fatalf("delete data error: %vn",err) } } func insertData(db *sql.DB) { stmt,_ := db.Prepare(`INSERT INTO user (id,age) VALUES (?,?,?)`) rows,err := stmt.Query(1,20) defer stmt.Close() rows.Close() if err != nil { log.Fatalf("insert data error: %vn",err = stmt.Query(2,"test",19) var result int rows.Scan(&result) log.Printf("insert result %vn",result) rows.Close() } func selectData(db *sql.DB) { var id int var name string var age int stmt,_ := db.Prepare(`SELECT * From user where age > ?`) rows,err := stmt.Query(10) defer stmt.Close() defer rows.Close() if err != nil { log.Fatalf("select data error: %vn",err) return } deleteData(db) insertData(db) selectData(db) } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |