首頁  >  文章  >  後端開發  >  go語言可以寫資料庫麼

go語言可以寫資料庫麼

青灯夜游
青灯夜游原創
2023-01-06 10:35:283985瀏覽

go語言可以寫入資料庫。 Go語言和其他語言不同的地方是,Go官方沒有提供資料庫驅動,而是編寫了開發資料庫驅動的標準接口,開發者可以根據定義的接口來開發相應的資料庫驅動;這樣做的好處在於,只要是依照標準介面開發的程式碼,以後遷移資料庫時,不需要做任何修改,極大方便了後期的架構調整。

go語言可以寫資料庫麼

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

資料庫(database)是依照資料結構來組織、儲存和管理資料的倉庫。相對於其他儲存方式,儲存只是資料庫的其中一個功能,資料的組織與管理才是資料庫的核心。

相較於資料庫,檔案保存資料的缺點:

  • 檔案有安全性問題
  • 檔案不利於對資料的查詢與管理
  • 文件不便於存放大量資料
  • 文件在程式中不便於控制

#資料庫的使用水準是衡量一個程式設計師能力的重要指標。

1、MySQL簡介

MySQL是一個關聯式資料庫管理系統,由瑞典MySQL AB公司開發,目前屬於甲骨文公司(Oracle )旗下產品。 MySQL是最受歡迎的關聯式資料庫管理系統之一,而在Web應用方面,MySQL是最好的RDBMS(Relational Database Management System,關聯式資料庫管理系統)應用軟體之一。

1.1 安裝MySQL

go語言可以寫資料庫麼

1.2 MySQL常見指令

> mysql -h主机地址 -u用户名 -p用户密码
  • 連接到本機上的MySQL

go語言可以寫資料庫麼

  • 連線到遠端主機上的MySQL

假設遠端主機的IP為:192.168.1.1,使用者名稱為root,密碼為root。

> mysql -h192.168.1.1 -uroot -proot
  • 退出MySQL指令
mysql> exit/quit;

#2、database/sql

Go操作資料庫,是透過database/sql套件以及第三方的實作了database/sql/driver介面的資料庫驅動包來共同完成的。

其中database/sql/driver中的介面Conn和Stmt,官方交給第三方實作驅動,並且是協程不安全的。官方實作的database/sql包中的DB和Stmt是協程安全的,因為內部實作是連接池。

Go語言和其他語言不同的地方是,Go官方沒有提供資料庫驅動,而是編寫了開發資料庫驅動的標準接口,開發者可以根據定義的接口來開發相應的資料庫驅動。這樣做的好處在於,只要是依照標準介面開發的程式碼,以後遷移資料庫時,不需要做任何修改,極大方便了後期的架構調整。

在每一個由第三方開發者編寫的資料庫驅動中,都會實作一個init函數,在init函數內會呼叫一個叫Register的方法來完成資料庫驅動的註冊。

func Register(name string, driver driver.Driver)

Register註冊並命名一個資料庫,可以在Open函數中使用該命名啟用該驅動程式。如果Register註冊相同名稱兩次,或driver參數為nil,會導致panic。

func init() {
    sql.Register("mysql", &MySQLDriver{})
}

套件在引入的過程中會自動呼叫套件中的init函數,因此,註冊資料庫驅動時只需要使用匿名導入的方式來引用該套件即可,這樣程式碼就可以直接使用這個資料庫驅動。

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

3、資料庫基本操作

#資料庫的最基本操作就是增(create)、查(read)、改(update )、刪(delete),簡稱CRUD。資料庫中有八類對象,分別是資料庫、資料表、記錄、欄位、索引、查詢、篩選器、視
圖。

3.1 連接資料庫

#Go語言中,sql套件提供了一個Open方法來建立一個資料庫連線。

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

Open開啟一個dirverName指定的資料庫,dataSourceName指定資料來源,一般至少包含資料庫檔案名稱和(可能的)連線資訊。

Open函數只是驗證其參數,而不建立與資料庫的連線。如果要檢查資料來源的名稱是否合法,應呼叫傳回值的Ping方法。

func (db *DB) Ping() error

Ping檢查與資料庫的連線是否仍有效,如果需要會建立連線。

package main

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

func main() {
   db, err := sql.Open("mysql", "root:200039@tcp(127.0.0.1:3306)/gostudy")
   if err != nil {
      log.Fatal(err)
   }
   defer db.Close()
   //验证连接的可用性
   err = db.Ping()
   if err != nil {
      log.Fatal("数据库连接失败:", err)
   }
   log.Println("数据库连接成功!")
}

go語言可以寫資料庫麼

#3.2 建立資料表

建立MySQL資料表需要定義表名、表格欄位名、欄位類型及約束。建立資料表語法結構為:

CREATE TABLE 表名 ( 
 	字段名1 数据类型 [列级别约束条件] [默认值],
 	字段名2 数据类型 [列级别约束条件] [默认值],
 	字段名3 数据类型 [列级别约束条件] [默认值],
 	... [表级别约束条件] 
);

建立一張資料表

CREATE TABLE `user`(
		`uid` INT(10) NOT NULL AUTO_INCREMENT,
		`username` VARCHAR(64) NULL DEFAULT 1,
		`gender` TINYINT(1) NULL DEFAULT NULL,
		`password` VARCHAR(64) NULL DEFAULT NULL,
		`created` DATE NULL DEFAULT NULL,
		PRIMARY KEY (`uid`)
);

go語言可以寫資料庫麼

使用Go语言创建数据表需要使用Exec函数。

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

Exec执行一次命令(包括查询、删除、更新、插入等),不返回任何执行结果。参数args表示query中的占位参数。

Exec的返回值为Result接口,Result的定义如下:

type Result interface {
 	LastInsertId() (int64, error)
 	RowsAffected() (int64, error)
}

Result主要有两个方法。LastInsertId返回一个数据库生成的回应命令的整数,当插入新行时,返回由数据库执行插入操作得到的自增ID号。RowsAffected返回被update、insert或delete命令影响的行数。

3.3 插入数据

MySQL中使用INSERT INTO语句来插入数据,插入的语法结构为:

INSERT INTO table_name ( field1, field2,...fieldN ) VALUES ( value1, value2,...valueN );

如果需要同时插入多条数据,可以使用如下方式:

INSERT INTO table_name (field1, field2,...fieldN) VALUES (valueA1,valueA2,...valueAN),(valueB1,valueB2,...value BN)......;
package main

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

func checkErr(err error) {
   if err != nil {
      log.Fatal(err)
   }
}

func main() {
   db, err := sql.Open("mysql", "root:200039@tcp(127.0.0.1:3306)/gostudy")
   checkErr(err)
   defer db.Close()

   //验证连接可用性
   err = db.Ping()
   checkErr(err)
   log.Println("数据库连接成功")

   rs, err := db.Exec("insert into `user`(username,gender,password,created) values (?,?,?,?)", "tom", 1, "123456", time.Now())
   checkErr(err)

   rowCount, err := rs.RowsAffected()
   checkErr(err)
   log.Printf("插入了 % d行", rowCount)
}

go語言可以寫資料庫麼

SQL注入(SQLi)是一种注入攻击,可以执行恶意SQL语句。它通过将任意SQL代码插入数据库查询,使攻击者能够完全控制Web应用程序后面的数据库服务器。攻击者可以使用SQL注入漏洞绕过应用程序安全措施;可以绕过网页或Web应用程序的身份验证和授权,并检索整个SQL数据库的内容;还可以使用SQL注入来添加、修改和删除数据库中的记录。

sql包还提供一种预编译的方式来执行SQL语句,通常在处理批量SQL语句时会用到这种方式,这种方式比手动拼接字符串SQL语句高效,还可以防止SQL注入攻击。

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

Prepare创建一个准备好的状态用于之后的查询和命令。返回值可以同时执行多个查询和命令。

package main

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

func checkErr(err error) {
   if err != nil {
      log.Fatal(err)
   }
}

func main() {
   db, err := sql.Open("mysql", "root:200039@tcp(127.0.0.1:3306)/gostudy")
   checkErr(err)
   defer db.Close()

   //验证连接可用性
   err = db.Ping()
   checkErr(err)
   log.Println("数据库连接成功")

   //rs, err := db.Exec("insert into `user`(username,gender,password,created) values (?,?,?,?)", "tom", 1, "123456", time.Now())
   stmt, err := db.Prepare("INSERT INTO `user`(username,gender,password,created) VALUES (?,?,?,?)")

   defer stmt.Close()
   rs, err := stmt.Exec("Ailsa", 0, "111111", time.Now())
   checkErr(err)
   rowCount, err := rs.RowsAffected()
   checkErr(err)
   log.Printf("插入了 % d行", rowCount)
}

go語言可以寫資料庫麼

3.4 查询数据

MySQL数据库使用SELECT语句来查询数据。以下为在MySQL数据库中查询数据通用的SELECT语法:

SELECT column_name,column_name
 FROM <表 1>, <表 2>...
 JOIN<表3>on...
 [WHERE <表达式>
 [GROUP BY <group by definition>
 [HAVING <expression> [{<operator> <expression>}...]]
 [ORDER BY <order by definition>]
 [LIMIT[<offset>,] <row count>]

语法解释:

  • SELECT之后是逗号分隔列或星号(*)的列表,表示要返回所有列。
  • FROM指定要查询数据的表或视图。
  • JOIN根据某些连接条件从其他表中获取数据。
  • WHERE过滤结果集中的行。
  • GROUP BY将一组行组合成小分组,并对每个小分组应用聚合函数。
  • HAVING过滤器是基于GROUP BY子句定义的小分组。
  • ORDER BY指定用于排序的列的列表。
  • LIMIT限制返回行的数量。

在Go语言中,我们可以使用Query函数来查询数据:

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

Query执行一次查询,返回多行结果(即Rows),一般用于执行SELECT命令。参数args表示
Query中的占位参数,Rows是查询的结果。它的游标指向结果集的第0行,使用Next方法来遍历各行结果。查询到数据后使用rows.Next获取一行结果,并使用Scan将查询到的结果赋值到目标变量中。

func (r *Row) Scan(dest ...interface{}) error
package main

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

type User struct {
   Uid      int
   Username string
   Gender   bool
   Password string
   Created  string
}

func checkErr(err error) {
   if err != nil {
      log.Fatal(err)
   }
}

func main() {
   db, err := sql.Open("mysql", "root:200039@tcp(127.0.0.1:3306)/gostudy")
   checkErr(err)
   defer db.Close()

   //验证连接的可用性
   err = db.Ping()
   checkErr(err)
   log.Println("数据库连接成功!")

   rows, err := db.Query("select * from `user` where username=?", "Tom")
   defer rows.Close()

   for rows.Next() {
      user := User{}
      err := rows.Scan(&user.Uid, &user.Username, &user.Gender, &user.Password, &user.Created)
      checkErr(err)

      log.Println(user)
   }

}

go語言可以寫資料庫麼

3.5 更改数据

如果需要修改或更新MySQL中的数据,我们可以使用UPDATE命令来操作。

UPDATE <表名> 
 SET 字段 1=值 1 [,字段 2=值 2... ] 
 [WHERE 子句 ]
 [ORDER BY 子句] 
 [LIMIT 子句]

语法解释:

  • <表名>:用于指定要更新的表名称。
  • SET:用于指定表中要修改的列名及其列值。其中,每个指定的列值可以是表达式,也可
    以是该列对应的默认值。如果指定的是默认值,可用关键字DEFAULT表示列值。
  • WHERE:可选。用于限定表中要修改的行。若不指定,则修改表中所有的行。
  • ORDER BY:可选。用于限定表中的行被修改的次序。
  • LIMIT:可选。用于限定被修改的行数。

注意:修改一行数据的多个列值时,SET子句的每个值用逗号分开即可。

rs, err := db.Exec("update `user` set password=? where sername=?","123123","john")
checkErr(err)
rowCount, err := rs.RowsAffected()
checkErr(err)
if rowCount > 0 {
  log.Println("更新成功!")
}

3.6 删除数据

MySQL使用DELETE语句从单个表中删除数据,语法格式为:

DELETE FROM <表名> 
 [WHERE 子句] 
 [ORDER BY 子句] 
 [LIMIT 子句]

语法解释:

  • <表名>:指定要删除数据的表名。
  • WHERE子句:可选项。表示为删除操作限定删除条件,若省略该子句,则代表删除该表中
    的所有行。
  • ORDER BY子句:可选项。表示删除时,表中各行将按照子句中指定的顺序进行删除。
  • LIMIT子句:可选项。用于告知服务器在控制命令被返回到客户端前被删除行的最大值。

注意:在不使用WHERE条件的时候,将删除所有数据;数据库一旦删除数据,数据就会永远
消失。因此,在执行DELETE语句之前,应该先备份数据库,以防需要找回被删除的数据。

rs, err := db.Exec("delete from `user` where uid=?",3)
checkErr(err)
rowCount, err := rs.RowsAffected()
checkErr(err)
if rowCount > 0 {
    log.Println("删除成功!")
}

3.7 MySQL事务

MySQL数据库中的事务是用户一系列的数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。

事务具有四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这四个特性简称为ACID原则。

  • 原子性

    事务必须是原子工作单元,事务中的操作要么全部执行,要么全都不执行,不能只完成部分操作。原子性在数据库系统中由恢复机制来实现。

  • 一致性

    事务开始之前,数据库处于一致性的状态;事务结束后,数据库必须仍处于一致性状态。数
    据库一致性的定义是由用户负责的。例如,在银行转账中,用户可以定义转账前后两个账户金额之和保持不变。

  • 隔离性

    系统必须保证事务不受其他并发执行事务的影响,即当多个事务同时运行时,各事务之间相
    互隔离,不可互相干扰。事务查看数据时数据所处的状态,要么是另一个并发事务修改它之前的状态,要么是另一个并发事务修改它之后的状态,事务不会查看中间状态的数据。隔离性通过系统的并发控制机制实现。

  • 持久性

    一个已完成的事务对数据所做的任何变动在系统中是永久有效的,即使该事务产生的修改不
    正确,错误也将一直保持。持久性通过恢复机制实现,发生故障时,可以通过日志等手段恢复数据库信息。

事务的ACID原则保证了一个事务或者成功提交,或者失败回滚,二者必居其一。因此,它对事务的修改具有可恢复性,即当事务失败时,它对数据的修改都会恢复到该事务执行前的状态。

简单来说,事务处理就两个过程,要么成功提交,要么失败回滚,在Go语言中使用Tx结构体来表示事务。

type Tx interface{
 Commit() error
 Rollback() error
}

Tx代表一个进行中的数据库事务。一次事务必须以对Commit或Rollback的调用结束。调用Commit或Rollback后,所有对事务的操作都会失败并返回错误值ErrTxDone。

package main

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

func checkErr(err error) {
   if err != nil {
      log.Fatal(err)
   }
}

func checkErrWithTx(err error, tx *sql.Tx) {
   if err != nil {
      tx.Rollback()
      log.Fatal(err)
   }
}

func main() {
   db, err := sql.Open("mysql", "root:200039@tcp(127.0.0.1:3306)/gostudy")
   checkErr(err)
   defer db.Close()

   //验证连接的可用性
   err = db.Ping()
   checkErr(err)
   log.Println("数据库连接成功!")

   var password string
   tx, err := db.Begin()
   checkErr(err)

   //查找Tom的密码,如果密码为123456就将密码改为111111,否则不执行任何操作
   err = tx.QueryRow("select password from `user` where username=?", "Tom").Scan(&password)
   checkErrWithTx(err, tx)
   if password == "123456" {
      rs, err := tx.Exec("update `user` set password=? where username=?", "111111", "Tom")
      checkErrWithTx(err, tx)
      rowCount, err := rs.RowsAffected()
      checkErrWithTx(err, tx)
      if rowCount > 0 {
         log.Println("密码更新完成!")
      }
   }
   tx.Commit()
   log.Println("事务处理完成!")
}

go語言可以寫資料庫麼

4、知识拓展

  • 数据库(Database)

    所谓“数据库”,是以一定方式存储在一起、能与多个用户共享、具有尽可能小的冗余度、
    与应用程序彼此独立的数据集合。MySQL中使用的数据库是关系型数据库(Relational Database)。一个数据库由一个或一组数据表组成。每个数据库都以文件的形式存放在磁盘上,即对应于一个物理文件。不同的数据库与物理文件对应的方式也不一样。

  • 数据表(Table)

    数据表简称表,由一组数据记录组成,数据库中的数据是以表为单位进行组织的。一个表是
    一组相关的按行排列的数据,每个表中都含有相同类型的信息。表实际上是一个二维表格,例如一个班所有学生的考试成绩可以存放在一个表中,表中的每一行对应一个学生,这一行包括学生的学号、姓名及各门课程成绩。

  • 记录(Record)

    表中的每一行称为一个记录,它由若干个字段组成。

  • 字段(Field)

    字段也称域。表中的每一列称为一个字段。每个字段都有相应的描述信息,如数据类型、数
    据宽度等。

  • 索引(Index)

    為了提高存取資料庫的效率,可以對資料庫使用索引。在較大的資料庫中尋找指定的記錄
    時,使用索引和不使用索引的效率有很大差異。索引實際上是一種特殊類型的表,其中含有關鍵字段的值(由用戶定義)和指向實際記錄位置的指針,這些值和指針按照特定的順序(也由用戶定義)存儲,從而能以較快的速度查找到所需的資料記錄。

  • 查詢(Query)

    查詢是一條SQL(結構化查詢語言)指令,用來從一個或多個表中取得一組指定的記錄,或
    對某個表執行指定的操作。當從資料庫讀取資料時,我們往往希望讀出的資料符合某些條件,並且能依照某個欄位排序。使用SQL可以讓這項操作容易實現且更有效。 SQL是非過程化語言(有人稱之為第四代語言),在用它來尋找指定的記錄時,只需指出要做什麼,不必說明如何做。每個語句可以看成是一個查詢,根據這個查詢,可以得到需要的查詢結果。

  • 過濾器(Filter)

    過濾器是資料庫的一個組成部分,它把索引和排序結合起來,用來設定條件,然後根據給定
    的條件輸出所需的資料。

  • 檢視(View)

    資料的檢視指的是查找到(或處理)的記錄數和顯示(或處理)這些記錄的順序。在一般情
    際上是一個二維表格,例如一個班級所有學生的考試成績可以存放在一個表中,表中的每一行對應一個學生,這一行包括學生的學號、姓名及各門課程成績。

【相關推薦:Go影片教學程式設計教學

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

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