1、下载 github.com包

golang的”database/sql”是操作数据库时常用的包,这个包定义了一些sql操作的接口,具体的实现还需要不同数据库的实现,mysql比较优秀的一个驱动是:github.com/go-sql-driver/mysql,在接口、驱动的设计上”database/sql”的实现非常优秀,

2、创建文件,导入包

在src目录下创建demo.go文件(用到多文件编程,详情参考:https://blog.csdn.net/weixin_42117918/article/details/81835628),导入数据库驱动

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)
​
注意:程序在操作数据库的时候只需要用到database/sql,而不需要直接使用数据库驱动,所以程序在导入数据库驱动的时候将这个包的名字设置成下划线。

3、通过sql.open()连接数据库

sql.open(驱动名,数据源dsn)(*DB,err)

数据源语法:"用户名:密码@[连接方式](主机名:端口号)/数据库名"

注意:open()在执行时不会真正的与数据库进行连接,只是设置连接数据库需要的参数
ping()方法才是连接数据库

4、代码实例:

其中,数据库中的表结构为:

package main

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

type User0 struct {
	Id   int
	Name string
	Age  int
}

var db0 *sql.DB

func init() {
	//parseTime:时间格式转换;
	// loc=Local解决数据库时间少8小时问题
	var err error
	//TODO 注意:一下语句不能使用:db0, err :=  ;不然将db0当做临时变量来处理,不会对全局变量db0进行赋值。
	db0, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/testdb?charset=utf8&parseTime=true&loc=Local")
	if err != nil {
		log.Fatal("数据库打开出现了问题:", err)
		return
	}
	//	defer db0.Close()
	// 尝试与数据库建立连接(校验dsn是否正确)
	err = db0.Ping()
	if err != nil {
		log.Fatal("数据库连接出现了问题:", err)
		return
	}

}
func main() {
	//queryRowDemo()
	//queryMultiRowDemo()
	//insertRowDemo()
	//updateRowDemo()
	//deleteRowDemo()
	//prepareQueryDemo()
	//prepareInsertDemo()
	//transactionDemo()
	sqlInjectDemo("张三")
}

// 查询单条数据示例
func queryRowDemo() {
	var u User0
	sqlStr := "select id, name, age from user0 where id=?"
	err:=db0.QueryRow(sqlStr,1).Scan(&u.Id,&u.Name,&u.Age)
	if err != nil {
		fmt.Printf("scan failed, err:%v\n", err)
		return
	}
	fmt.Printf("id:%d name:%s age:%d\n", u.Id, u.Name, u.Age)
}

// 查询多条数据示例
func queryMultiRowDemo() {
	sqlStr := "select id, name, age from user0 where id > ?"
	rows, err := db0.Query(sqlStr, 0)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	// 非常重要:关闭rows释放持有的数据库链接
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var u User0
		err := rows.Scan(&u.Id, &u.Name, &u.Age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id:%d name:%s age:%d\n", u.Id, u.Name, u.Age)
	}
}
// 插入数据
func insertRowDemo() {
	sqlStr := "insert into user0(name, age) values (?,?)"
	ret, err := db0.Exec(sqlStr, "王五", 22)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	theID, err := ret.LastInsertId() // 新插入数据的id
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}
	fmt.Printf("insert success, the id is %d.\n", theID)
}
// 更新数据
func updateRowDemo() {
	sqlStr := "update user0 set age=? where id = ?"
	ret, err := db0.Exec(sqlStr, 22, 3)
	if err != nil {
		fmt.Printf("update failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected() // 操作影响的行数
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows:%d\n", n)
}
// 删除数据
func deleteRowDemo() {
	sqlStr := "delete from user0 where id = ?"
	ret, err := db0.Exec(sqlStr, 3)
	if err != nil {
		fmt.Printf("delete failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected() // 操作影响的行数
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("delete success, affected rows:%d\n", n)
}
/*
Go中的
func (db *DB) Prepare(query string) (*Stmt, error)
Prepare方法会先将sql语句发送给MySQL服务端,返回一个准备好的状态用于之后的查询和命令。返回值可以同时执行多个查询和命令。
*/
// 预处理查询示例
func prepareQueryDemo() {
	sqlStr := "select id, name, age from user0 where id > ?"
	stmt, err := db0.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("prepare failed, err:%v\n", err)
		return
	}
	defer stmt.Close()
	rows, err := stmt.Query(0)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	defer rows.Close()
	// 循环读取结果集中的数据
	for rows.Next() {
		var u User0
		err := rows.Scan(&u.Id, &u.Name, &u.Age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id:%d name:%s age:%d\n", u.Id, u.Name, u.Age)
	}
}

/*
插入、更新和删除操作的预处理十分类似,这里以插入操作的预处理为例:
*/
// 预处理插入示例
func prepareInsertDemo() {
	sqlStr := "insert into user0(name, age) values (?,?)"
	stmt, err := db0.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("prepare failed, err:%v\n", err)
		return
	}
	defer stmt.Close()
	_, err = stmt.Exec("小王子", 18)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	_, err = stmt.Exec("沙河娜扎", 18)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	fmt.Println("insert success.")
}
/*
Go语言中使用以下三个方法实现MySQL中的事务操作。 开始事务

func (db *DB) Begin() (*Tx, error)
提交事务
func (tx *Tx) Commit() error

回滚事务
func (tx *Tx) Rollback() error

*/
// 事务操作示例
func transactionDemo() {
	tx, err := db0.Begin() // 开启事务
	if err != nil {
		if tx != nil {
			tx.Rollback() // 回滚
		}
		fmt.Printf("begin trans failed, err:%v\n", err)
		return
	}
	sqlStr1 := "Update user0 set age=28 where id=?"
	_, err = tx.Exec(sqlStr1, 4)
	if err != nil {
		tx.Rollback() // 回滚
		fmt.Printf("exec sql1 failed, err:%v\n", err)
		return
	}
	sqlStr2 := "Update user0 set age=29 where id=?"
	_, err = tx.Exec(sqlStr2, 5)
	if err != nil {
		tx.Rollback() // 回滚
		fmt.Printf("exec sql2 failed, err:%v\n", err)
		return
	}
	err = tx.Commit() // 提交事务
	if err != nil {
		tx.Rollback() // 回滚
		fmt.Printf("commit failed, err:%v\n", err)
		return
	}
	fmt.Println("exec trans success!")
}
/*
SQL注入

todo :  我们任何时候都不应该自己拼接SQL语句!
*/
// sql注入示例
func sqlInjectDemo(name string) {
	sqlStr := fmt.Sprintf("select id, name, age from user0 where name='%s'", name)
	fmt.Printf("SQL:%s\n", sqlStr)
	// todo :正确写法 sqlStr := "select id, name, age from user0 where name=?"
	var u User0
	err:=db0.QueryRow(sqlStr).Scan(&u.Id,&u.Name,&u.Age)
	if err != nil {
		fmt.Printf("scan failed, err:%v\n", err)
		return
	}
	fmt.Printf("id:%d name:%s age:%d\n", u.Id, u.Name, u.Age)
}

了解更多Go语言知识https://study.163.com/course/introduction/1210620804.htm

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐