1. Database/sql 的基本用法,设计原理,基础概念
什么是数据库?
- 数据库(Database, DB)是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。
- 用来管理数据库的计算机系统称为数据库管理系统(Database Management System,DBMS)。
- 为什么DBMS那么重要?因为文本文件或Excel的局限性:
-
- 无法多人共享数据
- 无法提供操作大量数据所需的格式
- 实现读写自动化需要编程能力
- 无法应对突发事故
- DBMS的种类
-
- 层次数据库(Hierarchical Database, HDB):最古老的数据库之一,它把数据通过层次结构(树形结构)的方式表现出来。
- 关系数据库(Relational Database, RDB):关系数据库是现在应用最广泛的数据库。
- 面向对象数据库(Object Oriented Database, OODB):把数据以及对数据的操作集合起来以对象为单位进行管理。
- XML数据库(XML Database, XMLDB):XML 数据库可以对 XML 形式的大量数据进行高速处理。
- 键值存储系统(Key-Value Store, KVS):这是一种单纯用来保存查询所使用的主键(Key)和值(Value)的组合的数据库。
什么是SQL?
SQL(Structured Query Language,结构化查询语言)是用来操作关系数据库的语言。
- SQL语句及其种类: SQL 用关键字、表名、列名等组合而成的一条语句(SQL 语句)来描述操作的内容。关键字是指那些含义或使用方法已事先定义好的英语单词,存在包含“对表进行查询”或者“参考这个表”等各种意义的关键字。根据对 RDBMS 赋予的指令种类的不同, SQL 语句可以分为以下三类。PS:实际使用的 SQL 语句当中有 90% 属于 DML。
-
- DDL(Data Definition Language,数据定义语言) 用来创建或者删除存储数据用的数据库以及数据库中的表等对象。 DDL 包含以下几种指令。
-
- CREATE: 创建数据库和表等对象
- DROP: 删除数据库和表等对象
- ALTER: 修改数据库和表等对象的结构
- DML(Data Manipulation Language,数据操纵语言) 用来查询或者变更表中的记录。 DML 包含以下几种指令。
-
- CREATE: 创建数据库和表等对象
- DROP: 删除数据库和表等对象
- ALTER: 修改数据库和表等对象的结构
- DCL(Data Control Language,数据控制语言) 用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对 RDBMS 的用户是否有权限操作数据库中的对象(数据库表等)进行设定。 DCL 包含以下几种指令。
-
- COMMIT: 确认对数据库中的数据进行的变更
- ROLLBACK: 取消对数据库中的数据进行的变更
- GRANT: 赋予用户操作权限
- REVOKE: 取消用户的操作权限
- SQL的基本书写规则:
-
- SQL语句要以分号(;)结尾;
- SQL语句不区分关键字大小写,插入表中的数据区分大小写;
- 常数的书写方式是固定的,字符串和日期常数需要使用单引号(')括起来,数字常数无需加注单引号(直接书写数字即可);
- 单词间需要用半角空格或者换行来分隔,不能使用全角空格作为单词的分隔符;
基本用法1
import driver 实现,使用driver + DSN 初始化 DB 连接;
执行一条SQL, 通过 rows 取回返回的数据 处理完毕,需要释放链接
设计原理
DB 连接的几种类型:
直接连接 Conn; 预编译 Stmt; 事务 Tx;
处理返回数据的几种方式:
Exec - ExecContext - Result; Query - QueryContext - Rows(Columns); QueryRow- QueryRowContext - Row(Row 简化);
GORM
特性: 设计简介,功能强大,自由扩展的全功能ORM; 设计原则: API 简洁,测试优先,最小惊讶,灵活扩展,无依赖;功能完善:关联,事务,多数据库,字段权限,代码生成,多模式自由扩展等;
ORM (Object Relational Mapping):对象关系映射
结构体 和 SQL数据库存在映射;
GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server;
MySQL
表操作
package main
import ( "gorm.io/driver/mysql" "gorm.io/gorm" )
type User struct {
Id int
Name string
Age int
Addr string
Pic string
}
func main() { // 用户名:密码@tcp(ip:port)/数据库?charset=utf8mb4&parseTime=True&loc=Local
dsn := "root:root123@tcp(127.0.0.1:3306)/test_gorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
}
- GORM 实践
连接检查
package mysql
import ( "testing" "time" )
func TestStaleConnectionChecks(t *testing.T) { runTests(t, dsn, func(dbt *DBTest) { dbt.mustExec("SET @@SESSION.wait_timeout = 2")
if err := dbt.db.Ping(); err != nil {
dbt.Fatal(err)
}
// wait for MySQL to close our connection
time.Sleep(3 * time.Second)
tx, err := dbt.db.Begin()
if err != nil {
dbt.Fatal(err)
}
if err := tx.Rollback(); err != nil {
dbt.Fatal(err)
}
})
}
连接检查设置
package mysql
import ( "errors" "io" "net" "syscall" )
var errUnexpectedRead = errors.New("unexpected read from socket")
func connCheck(conn net.Conn) error { var sysErr error
sysConn, ok := conn.(syscall.Conn)
if !ok {
return nil
}
rawConn, err := sysConn.SyscallConn()
if err != nil {
return err
}
err = rawConn.Read(func(fd uintptr) bool {
var buf [1]byte
n, err := syscall.Read(int(fd), buf[:])
switch {
case n == 0 && err == nil:
sysErr = io.EOF
case n > 0:
sysErr = errUnexpectedRead
case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK:
sysErr = nil
default:
sysErr = err
}
return true
})
if err != nil {
return err
}
return sysErr
}