首頁 >後端開發 >Golang >go語言中sql是什麼

go語言中sql是什麼

青灯夜游
青灯夜游原創
2022-12-22 11:55:4324769瀏覽

SQL是指“結構化查詢語言”,是一種操作資料庫的語言,包括建立資料庫、刪除資料庫、查詢記錄、修改記錄、新增欄位等。 SQL是關聯式資料庫的標準語言,所有的關聯式資料庫管理系統(RDBMS),例如 MySQL、Oracle、SQL Server、MS Access、Sybase、Informix、Postgres 等,都將 SQL 作為其標準處理語言。

go語言中sql是什麼

本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

SQL是什麼

SQL 是一種操作資料庫的語言,包括建立資料庫、刪除資料庫、查詢記錄、修改記錄、添加字段等。 SQL 雖然是一種被 ANSI 標準化的語言,但它有許多不同的實作版本。

SQL 是 Structured Query Language 的縮寫,中文譯為「結構化查詢語言」。 SQL 是一種電腦語言,用來儲存、檢索和修改關係型資料庫中儲存的資料。

SQL 是關聯式資料庫的標準語言,所有的關聯式資料庫管理系統(RDBMS),例如MySQL、Oracle、SQL Server、MS Access、Sybase、Informix、Postgres 等,都將SQL 作為其標準處理語言。

SQL 的用途

SQL 之所以廣受歡迎,是因為它具有以下用途:

  • 允許用戶訪問關係型資料庫系統中的資料;

  • 允許使用者描述資料;

  • 允許使用者定義資料庫中的數據,並處理該資料;

  • 允許將SQL 模組、函式庫或預處理器嵌入到其它程式語言中;

  • 允許使用者建立和刪除資料庫、表格、資料項(記錄);

  • 允許使用者在資料庫中建立視圖、預存程序、函數;

  • 允許使用者設定對錶、儲存過程和檢視的權限。

Go語言操作資料庫(MySQL)

#在Go語言標準函式庫提供了進行資料庫操作的sql 函式庫,可以利用SQL語言來操作資料庫。

1.1連線

#1.1.1下載依賴

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

#1.1.2使用MySQL驅動

func Open(driverName, dataSourceName string) (*DB, error)

Open開啟一個dirverName指定的資料庫dataSourceName指定資料來源,一般至少包括資料庫檔案名稱和其它連接必要的資訊。

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
   // DSN:Data Source Name
	dsn := "user:password@tcp(127.0.0.1:3306)/dbname"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}
	defer db.Close()  // 注意这行代码要写在上面err判断的下面
}

1.1.3 初始化連接

Open函數可能只是驗證其參數格式是否正確,實際上並不建立與資料庫的連線。如果要檢查資料來源的名稱是否真實有效,應該呼叫Ping方法

package main

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

//需要注意 这里需要引用自己的mysql文件

var db *sql.DB
func initDB()(err error)  {
	//账号 密码 端口号(tcp)127.0.0.1:3306 表名 字符集  校验时间
	dsn := "root:123456@tcp(127.0.0.1:3306)/gomysql?charset=utf8mb4&parseTime=true"
	//加载驱动
	//这里需要是=而不是:=因为我们是给全局变量(db)赋值
	db,err = sql.Open("mysql",dsn)
	if err!=nil {
		return err
	}
	//尝试和数据库建立连接(校验dsn正确)
	//然后用了ping命令
	err=db.Ping()
	if err!=nil {
		return err
	}
	return nil
}
func main() {
	err := initDB()
	if err!=nil {
		fmt.Printf("connect failed,err:%v\n",err)
		return
	}
}

1.1.4SetMaxOpenConns

SetMaxOpenConns設定與數據函式庫建立連線的最大數目。如果n大於0且小於最大閒置連線數,會將最大閒置連線數減少到符合最大開啟連線數的限制。如果n<=0,不會限制最大開啟連線數,預設為0(無限制)

#1.1.5SetMaxIdleConns

# #
func (db *DB) SetMaxIdleConns(n int)
連線池中的最大閒置連線數

如果n大於最大開啟連線數,則新的最大閒置連線數會減少到匹配最大開啟連線數的限制。如果

n<=0,不會保留閒置連線

1.2CRUD

#1.2.1 建置庫建置表格我們先在MySQL中建立一個名為

sql_test

的資料庫

CREATE DATABASE sql_test;
###進入該資料庫:###
use sql_test;
###執行下列指令建立一張用於測試的資料表:###
CREATE TABLE `user` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(20) DEFAULT &#39;&#39;,
    `age` INT(11) DEFAULT &#39;0&#39;,
    PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
## ##########1.2.2 查詢############單行查詢#########單行查詢###db.QueryRow()###執行一次查詢,並期望傳回最多一行結果(即Row)。 QueryRow總是傳回非nil的值,直到傳回值的Scan方法被呼叫時,才會傳回被延遲的錯誤。 (如:找不到結果)###
func (db *DB) QueryRow(query string, args ...interface{}) *Row
func queryRowDemo() {
   sqlStr := "select id, name, age from user where id=?"
   var u user
   // 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
   err := db.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 (db *DB) Query(query string, args ...interface{}) (*Rows, error)
// 查询多条数据示例
func queryMultiRowDemo() {
	sqlStr := "select id, name, age from user where id > ?"
	rows, err := db.Query(sqlStr, 0)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	// 非常重要:关闭rows释放持有的数据库链接
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var u user
		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)
	}
}
############1.2.3 插入數據#########插入、更新和刪除操作都使用###Exec###方法。 ###
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
###Exec執行一次指令(包括查詢、刪除、更新、插入等),傳回的Result是對已執行的SQL指令的總結。參數args表示query中的佔位參數。 ######具體插入資料範例程式碼如下:###
// 插入数据
func insertRowDemo() {
	sqlStr := "insert into user(name, age) values (?,?)"
	ret, err := db.Exec(sqlStr, "王五", 38)
	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)
}
#############1.2.4更新資料########具體更新資料範例程式碼如下: ###
// 更新数据
func updateRowDemo() {
	sqlStr := "update user set age=? where id = ?"
	ret, err := db.Exec(sqlStr, 39, 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)
}

1.2.5删除数据

具体删除数据的示例代码如下:

// 删除数据
func deleteRowDemo() {
	sqlStr := "delete from user where id = ?"
	ret, err := db.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)
}

总体

package main

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

// 定义一个全局对象db
var db *sql.DB

// 定义一个初始化数据库的函数
func initDB() (err error) {
	// DSN:Data Source Name
	dsn := "root:123456@tcp(127.0.0.1:3306)/sql_test?charset=utf8&parseTime=True"
	// 不会校验账号密码是否正确
	// 注意!!!这里不要使用:=,我们是给全局变量赋值,然后在main函数中使用全局变量db
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	// 尝试与数据库建立连接(校验dsn是否正确)
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}
type user struct {
	id   int
	age  int
	name string
}
func queryRowDemo() {
	sqlStr := "select id, name, age from user where id=?"
	var u user
	// 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
	err := db.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 user where id > ?"
	rows, err := db.Query(sqlStr, 0)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	// 非常重要:关闭rows释放持有的数据库链接
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var u user
		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 user(name,age) value (?,?)"
	//
	ret,err := db.Exec(sqlStr,"王五",40)
	if err!=nil {
		fmt.Printf("inserf failed,err:%v\n",err)
		return
	}
	//插入成功之后需要返回这个id
	theID,err:=ret.LastInsertId()
	if err != nil{
		fmt.Printf("get the last insertid failed,err:%v\n",theID)
		return
	}
	fmt.Printf("insert success,theID is:%v\n",theID)

}
func updateRowDemo()  {

	sqlStr := "update user set name =? where id = ?"
	//执行含有sqlStr参数的语句
	ret,err:=db.Exec(sqlStr,"赵四",4)
	if err!=nil {
		fmt.Printf("update failed,err:%v\n",err)
		return
	}
	AnoID,err:=ret.RowsAffected()
	if err!=nil {
		fmt.Printf("updateRowAffected failed,err:%v\n",err)
		return
	}
	fmt.Printf("update success AnoID:%v\n",AnoID)

}
// 删除数据
func deleteRowDemo() {
	sqlStr := "delete from user where id = ?"
	ret, err := db.Exec(sqlStr, 5)
	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)
}
func main() {
	err := initDB() // 调用输出化数据库的函数
	if err != nil {
		fmt.Printf("init db failed,err:%v\n", err)
		return
	}
	//queryRowDemo()
	//insertRowDemo()
    //updateRowDemo()
    deleteRowDemo()
	queryMultiRowDemo()
}

1.3MySQL预处理

1.3.1什么是预处理?

普通SQL语句执行过程:

  • 客户端对SQL语句进行占位符替换得到完整的SQL语句。

  • 客户端发送完整SQL语句到MySQL服务端

  • MySQL服务端执行完整的SQL语句并将结果返回给客户端

预处理执行过程:

  • 把SQL语句分成两部分,命令部分与数据部分

  • 先把命令部分发送给MySQL服务端MySQL服务端进行SQL预处理

  • 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换

  • MySQL服务端执行完整的SQL语句并将结果返回给客户端

1.3.2为什么要预处理?

  • 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本。

  • 避免SQL注入问题。

1.3.3 Go实现MySQL预处理

func (db *DB) Prepare(query string) (*Stmt, error)

查询操作的预处理示例代码如下:

// 预处理查询示例
func prepareQueryDemo() {
	sqlStr := "select id, name, age from user where id > ?"
	stmt, err := db.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 user
		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 user(name, age) values (?,?)"
	stmt, err := db.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.")
}

总结 其实就多了一个db.Prepare(sqlStr)

1.3.4 SQL注入问题

我们任何时候都不应该自己拼接SQL语句!

// sql注入示例
func sqlInjectDemo(name string) {
	sqlStr := fmt.Sprintf("select id, name, age from user where name=&#39;%s&#39;", name)
	fmt.Printf("SQL:%s\n", sqlStr)
	var u user
	err := db.QueryRow(sqlStr).Scan(&u.id, &u.name, &u.age)
	if err != nil {
		fmt.Printf("exec failed, err:%v\n", err)
		return
	}
	fmt.Printf("user:%#v\n", u)
}

此时以下输入字符串都可以引发SQL注入问题

sqlInjectDemo("xxx&#39; or 1=1#")
sqlInjectDemo("xxx&#39; union select * from user #")
sqlInjectDemo("xxx&#39; and (select count(*) from user) <10 #")
数据库 占位符语法
MySQL <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">?</span>
PostgreSQL $1, $2
SQLite ?$1
Oracle <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">:name</span>

【相关推荐:Go视频教程编程教学

以上是go語言中sql是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn