ホームページ >バックエンド開発 >Golang >Go言語のSQLとは何ですか

Go言語のSQLとは何ですか

青灯夜游
青灯夜游オリジナル
2022-12-22 11:55:4324760ブラウズ

SQL は「構造化照会言語」を指し、データベースの作成、データベースの削除、レコードのクエリ、レコードの変更、フィールドの追加など、データベースを操作するための言語です。 SQL はリレーショナル データベースの標準言語です。MySQL、Oracle、SQL Server、MS Access、Sybase、Informix、Postgres などのすべてのリレーショナル データベース管理システム (RDBMS) は、標準処理言語として SQL を使用します。

Go言語のSQLとは何ですか

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

SQL とは

SQL は、データベースの作成、データベースの削除、レコードのクエリ、レコードの変更、追加など、データベースを操作するための言語です。フィールドなどSQL は ANSI によって標準化された言語ですが、さまざまな実装があります。

SQL は Structured Query Language の略称で、中国語に訳すと「構造化照会言語」となります。 SQL は、リレーショナル データベースに保存されたデータの保存、取得、変更に使用されるコンピュータ言語です。

SQL はリレーショナル データベースの標準言語です。MySQL、Oracle、SQL Server、MS Access、Sybase、Informix、Postgres などのすべてのリレーショナル データベース管理システム (RDBMS) は、標準として 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 は保持されません。 1.2CRUD

1.2.1 データベースとテーブルの作成 まず、データベースを作成しましょう。 MySQL

sql_test

CREATE DATABASE sql_test;
という名前のデータベースを作成します。データベースを入力します。

use sql_test;

次のコマンドを実行して、テスト用のデータ テーブルを作成します。<pre class="brush:js;toolbar:false;">CREATE TABLE `user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) DEFAULT &amp;#39;&amp;#39;, `age` INT(11) DEFAULT &amp;#39;0&amp;#39;, PRIMARY KEY(`id`) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;</pre>

1.2.2 クエリ

単一行クエリ単一行クエリ

db.QueryRow()
クエリを実行すると、最大でも 1 行の結果 (つまり、行) が返されることが期待されます。 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 はコマンド (クエリ、削除、更新、挿入など) を実行し、返される結果は実行された SQL コマンドの概要です。パラメータ args は、クエリ内のプレースホルダ パラメータを表します。

データを挿入するための具体的なサンプル コードは次のとおりです。 <pre class="brush:js;toolbar:false;">// 插入数据 func insertRowDemo() { sqlStr := &quot;insert into user(name, age) values (?,?)&quot; ret, err := db.Exec(sqlStr, &quot;王五&quot;, 38) if err != nil { fmt.Printf(&quot;insert failed, err:%v\n&quot;, err) return } theID, err := ret.LastInsertId() // 新插入数据的id if err != nil { fmt.Printf(&quot;get lastinsert ID failed, err:%v\n&quot;, err) return } fmt.Printf(&quot;insert success, the id is %d.\n&quot;, theID) }</pre>

##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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。