Rumah >pembangunan bahagian belakang >Golang >Apakah sql dalam bahasa go

Apakah sql dalam bahasa go

青灯夜游
青灯夜游asal
2022-12-22 11:55:4324761semak imbas

SQL merujuk kepada "Bahasa Pertanyaan Berstruktur", iaitu bahasa untuk mengendalikan pangkalan data, termasuk mencipta pangkalan data, memadam pangkalan data, menanya rekod, mengubah suai rekod, menambah medan, dsb. SQL ialah bahasa standard untuk pangkalan data hubungan Semua sistem pengurusan pangkalan data hubungan (RDBMS), seperti MySQL, Oracle, SQL Server, MS Access, Sybase, Informix, Postgres, dll., menggunakan SQL sebagai bahasa pemprosesan standard mereka.

Apakah sql dalam bahasa go

Persekitaran pengendalian tutorial ini: sistem Windows 7, GO versi 1.18, komputer Dell G3.

Apakah itu SQL

SQL ialah bahasa untuk mengendalikan pangkalan data, termasuk mencipta pangkalan data, memadam pangkalan data, menyoal rekod, mengubah suai rekod dan menambah padang dll. Walaupun SQL ialah bahasa yang diseragamkan oleh ANSI, ia mempunyai banyak pelaksanaan yang berbeza.

SQL ialah singkatan dari Structured Query Language, yang diterjemahkan ke dalam bahasa Cina sebagai "Structured Query Language". SQL ialah bahasa komputer yang digunakan untuk menyimpan, mendapatkan semula dan mengubah suai data yang disimpan dalam pangkalan data hubungan.

SQL ialah bahasa standard untuk pangkalan data hubungan (RDBMS), seperti MySQL, Oracle, SQL Server, MS Access, Sybase, Informix, Postgres, dll., menggunakan SQL sebagai standard mereka. Bahasa pemprosesan.

Penggunaan SQL

SQL popular kerana penggunaannya:

  • Benarkan akses pengguna Data dalam sistem pangkalan data hubungan ;

  • membolehkan pengguna menerangkan data

  • membolehkan pengguna mentakrifkan data dalam pangkalan data dan memproses data

  • Membenarkan modul SQL, pustaka atau prapemproses dibenamkan ke dalam bahasa pengaturcaraan yang lain; 🎜>

  • membolehkan pengguna membuat paparan, prosedur tersimpan dan fungsi dalam pangkalan data

  • membolehkan pengguna menyediakan jadual dan Kebenaran storan untuk prosedur dan pandangan.

  • Pangkalan data operasi bahasa Go (MySQL)

Pustaka standard bahasa Go menyediakan perpustakaan sql untuk operasi pangkalan data , anda boleh menggunakan bahasa SQL untuk mengendalikan pangkalan data.

1.1 Sambungan

1.1.1 Muat Turun Ketergantungan

1.1.2 Gunakan pemacu MySQL
go get -u github.com/go-sql-driver/mysql

BukaBuka pangkalan data yang ditentukan oleh

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

dataSourceName menentukan sumber data , yang secara amnya termasuk sekurang-kurangnya nama fail pangkalan data dan maklumat lain yang diperlukan untuk sambungan.

1.1.3 Memulakan sambungan
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判断的下面
}

Fungsi Buka hanya boleh mengesahkan sama ada format parameternya betul, sebenarnya tidak membuat sambungan ke pangkalan data. Jika anda ingin menyemak sama ada nama sumber data adalah benar dan sah

, anda harus

panggil kaedah Ping

1.1.4SetMaxOpenConns
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
	}
}

Tetapkan bilangan maksimum sambungan yang diwujudkan dengan pangkalan data . Jika n lebih besar daripada 0 dan kurang daripada maksimum

bilangan sambungan melahu

, SetMaxOpenConnsbilangan maksimum sambungan melahu akan dikurangkan untuk memadankan had bilangan maksimum sambungan terbuka. Jika n<=0, bilangan maksimum sambungan terbuka tidak akan dihadkan Lalainya ialah 0 (tiada had)1.1.5SetMaxIdleConns<.>

Bilangan maksimum sambungan melahu dalam kolam sambungan

Jika n
func (db *DB) SetMaxIdleConns(n int)
lebih besar daripada bilangan maksimum sambungan terbuka

, bilangan maksimum sambungan melahu baharu akan dikurangkan Cukup kecil untuk sepadan dengan had bilangan maksimum sambungan terbuka. Jika

n<=0, sambungan melahu

tidak akan dikekalkan. 1.2CRUD

1.2.1 Membina pangkalan data dan jadualKami mula-mula mencipta pangkalan data dalam MySQL Cipta pangkalan data bernama

Masukkan pangkalan data:

sql_testLaksanakan arahan berikut untuk mencipta jadual data untuk ujian:

CREATE DATABASE sql_test;

use sql_test;

1.2.2 Pertanyaan

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;

Pertanyaan baris tunggalPertanyaan baris tunggal

Laksanakan pertanyaan sekali dan jangkakan Pulangan paling banyak satu baris hasil (iaitu Baris). QueryRow sentiasa mengembalikan nilai bukan nol dan tidak akan mengembalikan ralat tertunda sehingga kaedah Imbasan yang mengembalikan nilai dipanggil. (Contohnya: tiada hasil ditemui)

db.QueryRow()

Pertanyaan berbilang baris
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)
}
1.2.3 Memasukkan data
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)
	}
}

Sisip, kemas kini dan padam operasi semuanya menggunakan kaedah . Exec melaksanakan perintah (termasuk pertanyaan, padam, kemas kini, sisip, dll.), dan Hasil yang dikembalikan ialah ringkasan perintah SQL yang dilaksanakan. Parameter args mewakili parameter pemegang tempat dalam pertanyaan.

Kod sampel khusus untuk memasukkan data adalah seperti berikut: Exec

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

1.2.4 Kemas kini data

// 插入数据
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)
}

The kod sampel khusus untuk mengemas kini data Seperti berikut:
// 更新数据
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视频教程编程教学

Atas ialah kandungan terperinci Apakah sql dalam bahasa go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel sebelumnya:Apakah kelemahan bahasa go?Artikel seterusnya:Apakah kelemahan bahasa go?