Go语言

文章目录

  • Go语言
    • 20. 数据库编程
      • 20.1 MySQL简介
        • 20.1.1 安装MySQL
        • 20.1.2 MySQL常见命令
      • 20.2 database/sql
      • 20.3 数据库基本操作
        • 20.3.1 连接数据库
        • 20.3.2 创建数据表
        • 20.3.3 插入数据
        • 20.3.4 查询数据
        • 20.3.5 更改数据
        • 20.3.6 删除数据
        • 20.3.7 MySQL事务
      • 20.5 知识拓展

20. 数据库编程

数据库(database)是按照数据结构来组织、存储和管理数据的仓库。相对于其他存储方式,存储只是数据库的其中一个功能,数据的组织和管理才是数据库的核心。

相较于数据库,文件保存数据的缺点:

  • 文件有安全性问题
  • 文件不利于对数据的查询和管理
  • 文件不便于存放海量数据
  • 文件在程序中不便于控制

数据库的使用水平是衡量一个程序员能力的重要指标。

20.1 MySQL简介

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于甲骨文公司(Oracle)旗下产品。MySQL是最流行的关系型数据库管理系统之一,而在Web应用方面,MySQL是最好的RDBMS(Relational Database Management System,关系数据库管理系统)应用软件之一。

20.1.1 安装MySQL

20.1.2 MySQL常见命令
> mysql -h主机地址 -u用户名 -p用户密码
  • 连接到本机上的MySQL

  • 连接到远程主机上的MySQL

假设远程主机的IP为:192.168.1.1,用户名为root,密码为root。

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

20.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"
)

20.3 数据库基本操作

数据库的最基本操作便是增(create)、查(read)、改(update)、删(delete),简称CRUD。数据库中有八类对象,分别是数据库、数据表、记录、字段、索引、查询、过滤器、视
图。

20.3.1 连接数据库

Go语言中,sql包提供了一个Open方法来创建一个数据库连接。

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

Open打开一个dirverName指定的数据库,dataSourceName指定数据源,一般至少包括数据库文件名和(可能的)连接信息。

Open函数只是验证其参数,而不创建与数据库的连接。如果要检查数据源的名称是否合法,应调用返回值的Ping方法。

func (db *DB) Ping() error

Ping检查与数据库的连接是否仍有效,如果需要会创建连接。

package mainimport ("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("数据库连接成功!")
}

20.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语言创建数据表需要使用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命令影响的行数。

20.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 mainimport ("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)
}

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

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

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

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

package mainimport ("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)
}

20.3.4 查询数据

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

SELECT column_name,column_nameFROM <表 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 mainimport ("database/sql"_ "github.com/go-sql-driver/mysql""log"
)type User struct {Uid      intUsername stringGender   boolPassword stringCreated  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)}}

20.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("更新成功!")
}
20.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("删除成功!")
}
20.3.7 MySQL事务

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

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

  • 原子性

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

  • 一致性

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

  • 隔离性

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

  • 持久性

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

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

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

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

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

package mainimport ("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 stringtx, 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("事务处理完成!")
}

20.5 知识拓展

  1. 数据库(Database)

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

  2. 数据表(Table)

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

  3. 记录(Record)

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

  4. 字段(Field)

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

  5. 索引(Index)

    为了提高访问数据库的效率,可以对数据库使用索引。在较大的数据库里查找指定的记录
    时,使用索引和不使用索引的效率有很大差别。索引实际上是一种特殊类型的表,其中含有关键字段的值(由用户定义)和指向实际记录位置的指针,这些值和指针按照特定的顺序(也由用户定义)存储,从而能以较快的速度查找到所需要的数据记录。

  6. 查询(Query)

    查询是一条SQL(结构化查询语言)命令,用来从一个或多个表中获取一组指定的记录,或者
    对某个表执行指定的操作。当从数据库中读取数据时,我们往往希望读出的数据符合某些条件,并且能按某个字段排序。使用SQL可以使这一操作容易实现而且更加有效。SQL是非过程化语言(有人称其为第四代语言),在用它查找指定的记录时,只需指出做什么,不必说明如何做。每个语句可以看作是一个查询,根据这个查询,可以得到需要的查询结果。

  7. 过滤器(Filter)

    过滤器是数据库的一个组成部分,它把索引和排序结合起来,用来设置条件,然后根据给定
    的条件输出所需要的数据。

  8. 视图(View)

    数据的视图指的是查找到(或处理)的记录数和显示(或处理)这些记录的顺序。在一般情
    际上是一个二维表格,例如一个班所有学生的考试成绩可以存放在一个表中,表中的每一行对应一个学生,这一行包括学生的学号、姓名及各门课程成绩。

Go语言 数据库编程相关推荐

  1. java语言数据库编程_JAVA语言数据库编程实例详解

    本文主要向大家介绍了JAVA语言数据库编程实例详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. DOS命令登录MySQL数据库:mysql -h 127.0.0.1 -u root ...

  2. 实验四 数据库SQL语言基础编程

    -- 实验四 数据库SQL语言基础编程 -- 实验目的: --  掌握数据库查询语句的编写方法 --  掌握利用查询语言完成基本查询 --  掌握利用SQL语句完成数据的添加.删除.修改操作 -- 实 ...

  3. mysql 数据库编程_MySQL数据库编程(C++语言)

    MySQL数据库编程(C++语言) 发布时间:2018-05-24 21:06, 浏览次数:452 , 标签: MySQL 本文主要介绍使用C++语言连接和操作 MySQL 数据库的方法. 1. 准备 ...

  4. linux python开发环境sql数据迁移到mysql_运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程,把获取的信息存入数据库...

    运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程 有关前两篇的链接: 一.实验环境: Python2.7.10.pycharm.VM虚拟机.CentOS6.3.mys ...

  5. c语言sqlserver数据库头文件,Mysql的C语言API进行数据库编程

    数据编程基础知识,掌握C语言,熟悉简单的SQL语句,能够实现简单的增.删.查.改即INSERT.DELETE .SELECT.UPDATE语句,其中SELECT语句尤为重要,面试笔试中经常被问及.默认 ...

  6. 使用C语言调用mysql数据库编程实战以及技巧

    今天编写使用C语言调用mysql数据库编程实战以及技巧,为其他IT同行作为参考,当然有错误可以留言,共同学习. 一.mysql数据库的C语言常用接口API 1.首先当然是链接数据库mysql_real ...

  7. 数据库编程与设计—SQL语言

    一.SQL语言基础 1 什么是SQL 结构化查询语言结构化查询语言(Structured Query Language)简称 SQL(发音:sequal['si:kwəl]),是一种数据库查询和程序设 ...

  8. C语言连接MySQL数据库编程教程:超详细

    ** C语言连接MySQL数据库编程教程 ** 一.下载安装mysql.h库文件 我们使用的编译器一般为VC6.0或者VS,默认的都是32位编译器,所以我们下载的库文件也直接下载32位的就可以.下面附 ...

  9. C语言网络编程:多路IO select实现多客户端

    文章目录 阻塞式的服务器程序 多线程服务器程序 非阻塞式服务器程序 基于事件响应的服务器程序 事件响应服务器程序的实现`select` 阻塞式的服务器程序 我们接触过最多的最基础的网络通信模型为TCP ...

最新文章

  1. python飞机大战的实训心得体会-python之基础总结(飞机大战)
  2. 字符串函数 replace() 方法妙用
  3. 寄存器(cpu工作原理)
  4. TensorFlow的各种应用,你晓得不?
  5. java包管理之maven安装
  6. Linux CentOS如何汉化系统
  7. HDU - 3790 最短路径问题
  8. python webpy 开发文档_Python webpy微信公众号开发之 回复图文消息
  9. PID到底是个啥?来给你讲个故事
  10. 烽火HG680-MC_TTL免费升级固件及教程
  11. thinkphp 3.1.3 php版本,ThinkPHP
  12. 小米note3的开发者选项在哪里?怎么进入开发者模式?如何显示布局边界?
  13. java 调用 ictclas50_中科院分词ICTCLAS5.0_JNI 使用方法
  14. UnityWebRequest加载音频
  15. 视频教程-清华-尹成老师-Python爬虫day13-Python
  16. 手把手带你 arduino 开发:基于ESP32S 的第一个应用-红外测温枪(带引脚图)
  17. DDoS防护方式以及产品
  18. SAP_ALV(CL_SALV_TABLE)
  19. 15秒的倒计时和15分钟的倒计时
  20. 1Mbps的ECS服务器能干嘛?

热门文章

  1. 程序员绝不要做“IT民工”
  2. 北京农行研发中心面试总结(夏季实习生)
  3. 聚合支付备案机构为479家,首次出现注销聚合支付备案
  4. Spring Aop(五)——给Advice传递参数
  5. 全力以赴提升粮食产能,建设责任担当
  6. Faker生成测试数据
  7. spongycastle加密算法
  8. 4.11 数值分析: 求重根/带参数m的牛顿迭代法
  9. 怎么入驻亚马逊跨境电商平台?
  10. GO工具开发|基于网站API的子域名与IP反查工具(一)