목차
SetMaxOpenConns최대값을 설정해야 합니다. 데이터베이스 연결 수 . n이 0보다 크고 최대 유휴 연결 수보다 작은 경우, " >SetMaxOpenConns최대값을 설정해야 합니다. 데이터베이스 연결 수 . n이 0보다 크고 최대 유휴 연결 수보다 작은 경우,
1.1.5SetMaxIdleConns" >1.1.5SetMaxIdleConns
1.2CRUD" >1.2CRUD
1.2.1 建库建表
1.2.2 查询" >1.2.2 查询
单行查询
多行查询" >多行查询
1.2.3 插入数据" >1.2.3 插入数据
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
로그인 후 복사
The 최대 유휴 연결 풀 번호 " >
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
로그인 후 복사
The 최대 유휴 연결 풀 번호
🎜단일 행 쿼리🎜
🎜🎜다중 행 쿼리🎜" >🎜🎜다중 행 쿼리🎜
1.2.5删除数据" >1.2.5删除数据
总体" >总体
1.3MySQL预处理" >1.3MySQL预处理
1.3.1什么是预处理?
1.3.2为什么要预处理?" >1.3.2为什么要预处理?
1.3.3 Go实现MySQL预处理" >1.3.3 Go实现MySQL预处理
总结 其实就多了一个db.Prepare(sqlStr)" >总结 其实就多了一个db.Prepare(sqlStr)
1.3.4 SQL注入问题" >1.3.4 SQL注入问题
백엔드 개발 Golang Go 언어에서 SQL이란 무엇입니까?

Go 언어에서 SQL이란 무엇입니까?

Dec 22, 2022 am 11:55 AM
golang 언어로 가다

SQL은 "Structured Query Language"를 말하며 데이터베이스 생성, 데이터베이스 삭제, 레코드 쿼리, 레코드 수정, 필드 추가 등 데이터베이스를 운영하기 위한 언어입니다. 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의 약어로, 중국어로 "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 Connect

1.1.1 종속성 다운로드

1

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

로그인 후 복사
1.1.2 MySQL 드라이버 사용

1

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

로그인 후 복사
OpenOpen a dirverName

,

dataSourceName으로 지정됨 지정된 데이터 소스에는 일반적으로 최소한 데이터베이스 파일 이름과 연결에 필요한 기타 정보가 포함됩니다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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 메소드를 호출

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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인 경우 열린 연결의 최대 개수는 제한되지 않습니다. SetMaxOpenConns设置与数据库建立连接的最大数目。 如果n大于0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。 如果n<=0,不会限制最大开启连接数,默认为0(无限制)

1.1.5SetMaxIdleConns

1

func (db *DB) SetMaxIdleConns(n int)

로그인 후 복사

连接池中的最大闲置连接数

如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。 如果n<=0,不会保留闲置连接

1.2CRUD

1.2.1 建库建表

我们先在MySQL中创建一个名为sql_test的数据库

1

CREATE DATABASE sql_test;

로그인 후 복사

进入该数据库:

1

use sql_test;

로그인 후 복사

执行以下命令创建一张用于测试的数据表:

1

2

3

4

5

6

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方法被调用时,才会返回被延迟的错误。(如:未找到结果)

1

func (db *DB) QueryRow(query string, args ...interface{}) *Row

로그인 후 복사

1

2

3

4

5

6

7

8

9

10

11

func queryRowDemo() {

   sqlStr := &quot;select id, name, age from user where id=?&quot;

   var u user

   // 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放

   err := db.QueryRow(sqlStr, 1).Scan(&amp;u.id, &amp;u.name, &amp;u.age)

   if err != nil {

      fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

      return

   }

   fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, u.id, u.name, u.age)

}

로그인 후 복사
多行查询

1

func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

로그인 후 복사

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// 查询多条数据示例

func queryMultiRowDemo() {

    sqlStr := &quot;select id, name, age from user where id &gt; ?&quot;

    rows, err := db.Query(sqlStr, 0)

    if err != nil {

        fmt.Printf(&quot;query failed, err:%v\n&quot;, err)

        return

    }

    // 非常重要:关闭rows释放持有的数据库链接

    defer rows.Close()

 

    // 循环读取结果集中的数据

    for rows.Next() {

        var u user

        err := rows.Scan(&amp;u.id, &amp;u.name, &amp;u.age)

        if err != nil {

            fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

            return

        }

        fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, u.id, u.name, u.age)

    }

}

로그인 후 복사

1.2.3 插入数据

插入、更新和删除操作都使用Exec기본값은 0(제한 없음)입니다.

1.1.5SetMaxIdleConns

1

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

로그인 후 복사
The 최대 유휴 연결 풀 번호

의 연결 n

이 최대 열린 연결 수🎜보다 큰 경우 새로운 최대 유휴 연결 수는 최대 열린 연결 수🎜의 제한 🎜과 일치하도록 줄어듭니다. 🎜n<=0이면 유휴 연결 🎜이 유지되지 않습니다. 🎜🎜🎜🎜1.2CRUD🎜🎜🎜🎜1.2.1 데이터베이스 및 테이블 구축🎜🎜🎜먼저 MySQL에서 sql_test라는 데이터베이스를 생성합니다🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 插入数据

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)

}

로그인 후 복사
🎜 데이터베이스를 입력합니다 : 🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 更新数据

func updateRowDemo() {

    sqlStr := &quot;update user set age=? where id = ?&quot;

    ret, err := db.Exec(sqlStr, 39, 3)

    if err != nil {

        fmt.Printf(&quot;update failed, err:%v\n&quot;, err)

        return

    }

    n, err := ret.RowsAffected() // 操作影响的行数

    if err != nil {

        fmt.Printf(&quot;get RowsAffected failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;update success, affected rows:%d\n&quot;, n)

}

로그인 후 복사
로그인 후 복사
🎜다음 명령을 실행하여 테스트용 데이터 테이블을 생성합니다. 🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 删除数据

func deleteRowDemo() {

    sqlStr := &quot;delete from user where id = ?&quot;

    ret, err := db.Exec(sqlStr, 3)

    if err != nil {

        fmt.Printf(&quot;delete failed, err:%v\n&quot;, err)

        return

    }

    n, err := ret.RowsAffected() // 操作影响的行数

    if err != nil {

        fmt.Printf(&quot;get RowsAffected failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;delete success, affected rows:%d\n&quot;, n)

}

로그인 후 복사
로그인 후 복사
🎜
🎜🎜1.2.2 Query🎜🎜
🎜단일 행 쿼리🎜
🎜Single -row query db.QueryRow()는 쿼리를 실행하고 최대 한 행의 결과(예: Row)를 반환할 것으로 예상합니다. QueryRow는 항상 nil이 아닌 값을 반환하며 값을 반환하는 Scan 메서드가 호출될 때까지 지연된 오류를 반환하지 않습니다. (예: 결과 없음)🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

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 := &quot;select id, name, age from user where id &gt; ?&quot;

    rows, err := db.Query(sqlStr, 0)

    if err != nil {

        fmt.Printf(&quot;query failed, err:%v\n&quot;, err)

        return

    }

    // 非常重要:关闭rows释放持有的数据库链接

    defer rows.Close()

 

    // 循环读取结果集中的数据

    for rows.Next() {

        var u user

        err := rows.Scan(&amp;u.id, &amp;u.name, &amp;u.age)

        if err != nil {

            fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

            return

        }

        fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, 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

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

로그인 후 복사
로그인 후 복사
🎜🎜다중 행 쿼리🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<a id="_145">// 预处理查询示例

func prepareQueryDemo() {

    sqlStr := &quot;select id, name, age from user where id &gt; ?&quot;

    stmt, err := db.Prepare(sqlStr)

    if err != nil {

        fmt.Printf(&quot;prepare failed, err:%v\n&quot;, err)

        return

    }

    defer stmt.Close()

    rows, err := stmt.Query(0)

    if err != nil {

        fmt.Printf(&quot;query failed, err:%v\n&quot;, err)

        return

    }

    defer rows.Close()

    // 循环读取结果集中的数据

    for rows.Next() {

        var u user

        err := rows.Scan(&amp;u.id, &amp;u.name, &amp;u.age)

        if err != nil {

            fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

            return

        }

        fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, u.id, u.name, u.age)

    }

}</a>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<a id="_145">// 预处理插入示例

func prepareInsertDemo() {

    sqlStr := &quot;insert into user(name, age) values (?,?)&quot;

    stmt, err := db.Prepare(sqlStr)

    if err != nil {

        fmt.Printf(&quot;prepare failed, err:%v\n&quot;, err)

        return

    }

    defer stmt.Close()

    _, err = stmt.Exec(&quot;小王子&quot;, 18)

    if err != nil {

        fmt.Printf(&quot;insert failed, err:%v\n&quot;, err)

        return

    }

    _, err = stmt.Exec(&quot;沙河娜扎&quot;, 18)

    if err != nil {

        fmt.Printf(&quot;insert failed, err:%v\n&quot;, err)

        return

    }

    fmt.Println(&quot;insert success.&quot;)

}</a>

🎜🎜🎜1.2.3 데이터 삽입🎜🎜 🎜 삽입, 업데이트 및 삭제 작업은 모두 Exec 메서드를 사용합니다. 🎜

1

2

3

4

5

6

7

8

9

10

11

12

// sql注入示例

func sqlInjectDemo(name string) {

    sqlStr := fmt.Sprintf(&quot;select id, name, age from user where name=&#39;%s&#39;&quot;, name)

    fmt.Printf(&quot;SQL:%s\n&quot;, sqlStr)

    var u user

    err := db.QueryRow(sqlStr).Scan(&amp;u.id, &amp;u.name, &amp;u.age)

    if err != nil {

        fmt.Printf(&quot;exec failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;user:%#v\n&quot;, u)

}

로그인 후 복사
로그인 후 복사
🎜Exec는 명령(쿼리, 삭제, 업데이트, 삽입 등 포함)을 실행하고 반환된 결과는 실행된 SQL 명령의 요약입니다. 매개변수 args는 쿼리의 자리 표시자 매개변수를 나타냅니다. 🎜🎜데이터 삽입을 위한 구체적인 샘플 코드는 다음과 같습니다. 🎜

1

2

3

sqlInjectDemo(&quot;xxx&#39; or 1=1#&quot;)

sqlInjectDemo(&quot;xxx&#39; union select * from user #&quot;)

sqlInjectDemo(&quot;xxx&#39; and (select count(*) from user) &lt;10 #&quot;)

로그인 후 복사
로그인 후 복사
🎜🎜🎜🎜1.2.4 데이터 업데이트🎜🎜🎜데이터 업데이트를 위한 구체적인 샘플 코드는 다음과 같습니다. 🎜

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 更新数据

func updateRowDemo() {

    sqlStr := &quot;update user set age=? where id = ?&quot;

    ret, err := db.Exec(sqlStr, 39, 3)

    if err != nil {

        fmt.Printf(&quot;update failed, err:%v\n&quot;, err)

        return

    }

    n, err := ret.RowsAffected() // 操作影响的行数

    if err != nil {

        fmt.Printf(&quot;get RowsAffected failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;update success, affected rows:%d\n&quot;, n)

}

로그인 후 복사
로그인 후 복사

1.2.5删除数据

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 删除数据

func deleteRowDemo() {

    sqlStr := &quot;delete from user where id = ?&quot;

    ret, err := db.Exec(sqlStr, 3)

    if err != nil {

        fmt.Printf(&quot;delete failed, err:%v\n&quot;, err)

        return

    }

    n, err := ret.RowsAffected() // 操作影响的行数

    if err != nil {

        fmt.Printf(&quot;get RowsAffected failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;delete success, affected rows:%d\n&quot;, n)

}

로그인 후 복사
로그인 후 복사

总体

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

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 := &quot;select id, name, age from user where id &gt; ?&quot;

    rows, err := db.Query(sqlStr, 0)

    if err != nil {

        fmt.Printf(&quot;query failed, err:%v\n&quot;, err)

        return

    }

    // 非常重要:关闭rows释放持有的数据库链接

    defer rows.Close()

 

    // 循环读取结果集中的数据

    for rows.Next() {

        var u user

        err := rows.Scan(&amp;u.id, &amp;u.name, &amp;u.age)

        if err != nil {

            fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

            return

        }

        fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, 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预处理

1

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

로그인 후 복사
로그인 후 복사

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// 预处理查询示例

func prepareQueryDemo() {

    sqlStr := &quot;select id, name, age from user where id &gt; ?&quot;

    stmt, err := db.Prepare(sqlStr)

    if err != nil {

        fmt.Printf(&quot;prepare failed, err:%v\n&quot;, err)

        return

    }

    defer stmt.Close()

    rows, err := stmt.Query(0)

    if err != nil {

        fmt.Printf(&quot;query failed, err:%v\n&quot;, err)

        return

    }

    defer rows.Close()

    // 循环读取结果集中的数据

    for rows.Next() {

        var u user

        err := rows.Scan(&amp;u.id, &amp;u.name, &amp;u.age)

        if err != nil {

            fmt.Printf(&quot;scan failed, err:%v\n&quot;, err)

            return

        }

        fmt.Printf(&quot;id:%d name:%s age:%d\n&quot;, u.id, u.name, u.age)

    }

}

로그인 후 복사
로그인 후 복사

插入、更新和删除操作的预处理十分类似,这里以插入操作的预处理为例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 预处理插入示例

func prepareInsertDemo() {

    sqlStr := &quot;insert into user(name, age) values (?,?)&quot;

    stmt, err := db.Prepare(sqlStr)

    if err != nil {

        fmt.Printf(&quot;prepare failed, err:%v\n&quot;, err)

        return

    }

    defer stmt.Close()

    _, err = stmt.Exec(&quot;小王子&quot;, 18)

    if err != nil {

        fmt.Printf(&quot;insert failed, err:%v\n&quot;, err)

        return

    }

    _, err = stmt.Exec(&quot;沙河娜扎&quot;, 18)

    if err != nil {

        fmt.Printf(&quot;insert failed, err:%v\n&quot;, err)

        return

    }

    fmt.Println(&quot;insert success.&quot;)

}

로그인 후 복사
로그인 후 복사

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

1.3.4 SQL注入问题

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

1

2

3

4

5

6

7

8

9

10

11

12

// sql注入示例

func sqlInjectDemo(name string) {

    sqlStr := fmt.Sprintf(&quot;select id, name, age from user where name=&#39;%s&#39;&quot;, name)

    fmt.Printf(&quot;SQL:%s\n&quot;, sqlStr)

    var u user

    err := db.QueryRow(sqlStr).Scan(&amp;u.id, &amp;u.name, &amp;u.age)

    if err != nil {

        fmt.Printf(&quot;exec failed, err:%v\n&quot;, err)

        return

    }

    fmt.Printf(&quot;user:%#v\n&quot;, u)

}

로그인 후 복사
로그인 후 복사

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

1

2

3

sqlInjectDemo(&quot;xxx&#39; or 1=1#&quot;)

sqlInjectDemo(&quot;xxx&#39; union select * from user #&quot;)

sqlInjectDemo(&quot;xxx&#39; and (select count(*) from user) &lt;10 #&quot;)

로그인 후 복사
로그인 후 복사

数据库 占位符语法
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으로 문의하세요.

뜨거운 기사 태그

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Golang을 사용하여 파일을 안전하게 읽고 쓰는 방법은 무엇입니까? Golang을 사용하여 파일을 안전하게 읽고 쓰는 방법은 무엇입니까? Jun 06, 2024 pm 05:14 PM

Golang을 사용하여 파일을 안전하게 읽고 쓰는 방법은 무엇입니까?

Golang 데이터베이스 연결을 위한 연결 풀을 구성하는 방법은 무엇입니까? Golang 데이터베이스 연결을 위한 연결 풀을 구성하는 방법은 무엇입니까? Jun 06, 2024 am 11:21 AM

Golang 데이터베이스 연결을 위한 연결 풀을 구성하는 방법은 무엇입니까?

Golang과 C++의 유사점과 차이점 Golang과 C++의 유사점과 차이점 Jun 05, 2024 pm 06:12 PM

Golang과 C++의 유사점과 차이점

golang 프레임워크 아키텍처의 학습 곡선은 얼마나 가파르나요? golang 프레임워크 아키텍처의 학습 곡선은 얼마나 가파르나요? Jun 05, 2024 pm 06:59 PM

golang 프레임워크 아키텍처의 학습 곡선은 얼마나 가파르나요?

Golang의 목록에서 임의의 요소를 생성하는 방법은 무엇입니까? Golang의 목록에서 임의의 요소를 생성하는 방법은 무엇입니까? Jun 05, 2024 pm 04:28 PM

Golang의 목록에서 임의의 요소를 생성하는 방법은 무엇입니까?

golang 프레임워크의 장점과 단점 비교 golang 프레임워크의 장점과 단점 비교 Jun 05, 2024 pm 09:32 PM

golang 프레임워크의 장점과 단점 비교

Golang 프레임워크의 오류 처리에 대한 모범 사례는 무엇입니까? Golang 프레임워크의 오류 처리에 대한 모범 사례는 무엇입니까? Jun 05, 2024 pm 10:39 PM

Golang 프레임워크의 오류 처리에 대한 모범 사례는 무엇입니까?

golang 프레임워크의 장점은 무엇인가요? golang 프레임워크의 장점은 무엇인가요? Jun 06, 2024 am 10:26 AM

golang 프레임워크의 장점은 무엇인가요?

See all articles