数据库标准开发

驱动

连接数据库是典型的CS变成,服务器端被动等待客户端建立TCP连接,并在此连接上进行特定的应用层协议。但是一般用户并不需要了解这些细节,这些都被打包到了驱动库中,只需要简单的调用打开就可以指定协议连接到指定的数据库中

数据库的种类和产品太多,协议太多,Go官方很难提供针对不同数据库的驱动程序,往往由各数据库官方或第三方给出不同开发语言的驱动库。但是,为了Go语言可以提前定义操作一个数据库的所有行为(接口)和数据(结构体)的规范,这些定义在databasq/sql下。

mysql驱动:

安装mysql的驱动

$ go get -u github.com/go-sql-driver/mysql

导入

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

注册驱动

// github.com/go-sql-driver/mysql/mysql/driver.go 代码中有注册驱动
func init() { // 83 行
	sql.Register("mysql", &MySQLDriver{})
}
连接

DSN 例子 :https://github.com/go-sql-driver/mysql#Examples

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

username:password@protocol(address)/dbname?param=value

connstr := "root:123456@tcp(127.0.0.1:3306)/test"
connstr := "root:123456@tcp/test"
connstr := "root:123456@/test"
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

var db *sql.DB

func init() {
	connect := "root:123456@tcp(127.0.0.1:3306)/test"
	var err error
	db, err = sql.Open("mysql", connect)
	if err != nil {
		fmt.Println(err)
	}
	db.SetConnMaxLifetime(time.Second * 30) //最大连接存活时间
	db.SetMaxOpenConns(10)                  // 最大连接数
	db.SetMaxIdleConns(10)                  // 最大闲置连接
}
func main() {
	fmt.Println(db)

}

db类型是*sql.DB, 是一个操作数据库的句柄,底层是一个多协程安全的连接池。

操作
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"time"
)

var db *sql.DB

func init() {
	connect := "root:123456@tcp(127.0.0.1:3306)/test"
	var err error
	db, err = sql.Open("mysql", connect)
	if err != nil {
		fmt.Println(err)
	}
	db.SetConnMaxLifetime(time.Second * 30) //最大连接存活时间
	db.SetMaxOpenConns(10)                  // 最大连接数
	db.SetMaxIdleConns(10)                  // 最大闲置连接
}

type Emp struct {
	emp_no     int
	birth_date string
	first_name string
	last_name  string
	gender     int
	hire_date  string
}

func main() {
	//fmt.Println(db)
	var e Emp
	row := db.QueryRow("select * from employees where emp_no = 10013")
	fmt.Println(row)
	err := row.Scan(&e.emp_no, &e.birth_date, &e.first_name, &e.last_name, &e.gender, &e.hire_date)
	if err != nil {
		log.Panic(err)
	}
	fmt.Println(e)

	fmt.Println("~~~~~~~~~~~~~~~~~~~~")

	rows, err := db.Query("select * from employees where emp_no > ?", 10017)
	if err != nil {
		log.Panic(err)
	}

	for rows.Next() {
		var e Emp
		err := rows.Scan(&e.emp_no, &e.birth_date, &e.first_name, &e.last_name, &e.gender, &e.hire_date)
		if err != nil {
			log.Panic(err)
		}
		fmt.Println(e)
	}
}
  • 驱动安装和导入,例如import _ "github.com/go-sql-driver/mysql"
  • 连接数据库并返回数据库操作句柄,例如 sql.Open("mysql","dujie:123456@tcp(localhost:3306)/test")
  • 使用db提供的接口函数
  • 使用db.Prepare预编译并使用参数化查询
    • 对预编译的SQL语句进行缓存,省去了每次解析优化该SQL语句的过程
    • 防止注入攻击
    • 使用返回的sql.Stmt操作数据库
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"time"
)

var db *sql.DB

func init() {
	connect := "root:123456@tcp(127.0.0.1:3306)/test"
	var err error
	db, err = sql.Open("mysql", connect)
	if err != nil {
		fmt.Println(err)
	}
	db.SetConnMaxLifetime(time.Second * 30) //最大连接存活时间
	db.SetMaxOpenConns(10)                  // 最大连接数
	db.SetMaxIdleConns(10)                  // 最大闲置连接
}

type Emp struct {
	emp_no     int
	birth_date string
	first_name string
	last_name  string
	gender     int
	hire_date  string
}

func main() {
	//fmt.Println(db)
	var e Emp
	row := db.QueryRow("select * from employees where emp_no = 10013")
	fmt.Println(row)
	err := row.Scan(&e.emp_no, &e.birth_date, &e.first_name, &e.last_name, &e.gender, &e.hire_date)
	if err != nil {
		log.Panic(err)
	}
	fmt.Println(e)

	fmt.Println("~~~~~~~~~~~~~~~~~~~~")

	stmt, _ := db.Prepare("select * from employees where emp_no > ?")
	rows, err := stmt.Query(10017)
	if err != nil {
		fmt.Println(err)
	}
	for rows.Next() {
		var e Emp
		rows.Scan(&e.emp_no, &e.birth_date, &e.first_name, &e.last_name, &e.gender, &e.hire_date)
		fmt.Println(e)
	}
}
插入、修改、删除

增删改其实操作都一样,都是通过exec来控制

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"time"
)

var db *sql.DB

func init() {
	connect := "root:123456@tcp(127.0.0.1:3306)/test"
	var err error
	db, err = sql.Open("mysql", connect)
	if err != nil {
		fmt.Println(err)
	}
	db.SetConnMaxLifetime(time.Second * 30) //最大连接存活时间
	db.SetMaxOpenConns(10)                  // 最大连接数
	db.SetMaxIdleConns(10)                  // 最大闲置连接
}

type Emp struct {
	emp_no     int
	birth_date string
	first_name string
	last_name  string
	gender     int
	hire_date  string
}

func main() {
        // 增加
	//var e Emp
	result, err := db.Exec("insert into employees(emp_no,birth_date,first_name,last_name,gender,hire_date) values(10023,'1980-01-01','John','tom',1,'2006-01-02')")
	if err != nil {
		log.Panicln(err)
	}
	fmt.Println(result)

    // 删除
    stmt, errs := db.Prepare("delete from titles where emp_no=?")
    fmt.Println(errs)
    if errs != nil {
        fmt.Println(errs)
    }
    result, errd := stmt.Exec(10016)
    if errd != nil {
        log.Fatalln(errd)
    }
    fmt.Println(result)

    // 修改
    result, erra := db.Exec("update titles set title = ? where emp_no=?", "dujie", 10014)
    if erra != nil {
        log.Fatal(erra)
    }
    fmt.Println(result)

}