Go_MySQL查询插入删除
什么是预处理?
普通SQL语句执行过程:
- 客户端对SQL语句进行占位符替换得到完整的SQL语句。
- 客户端发送完整SQL语句到MySQL服务端
- MySQL服务端执行完整的SQL语句并将结果返回给客户端。
预处理执行过程:
- 把SQL语句分成两部分,命令部分与数据部分。
- 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。
- 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换。
- MySQL服务端执行完整的SQL语句并将结果返回给客户端。
为什么要预处理?
- 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本。
- 避免SQL注入问题。
Go实现MySQL预处理
Go中的
func (db *DB) Prepare(query string) (*Stmt, error)
Prepare
方法会先将sql语句发送给MySQL服务端,返回一个准备好的状态用于之后的查询和命令。返回值可以同时执行多个查询和命令。
package main import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql" // init()
) // Go连接MySQL示例 var db *sql.DB // db是一个连接池对象,每次操作会从连接池中取一个db对象来服务 func initDB() (err error) {
// 数据库信息
// 用户名:密码@tcp(ip:端口)/数据库的名字
dsn := "root:root@tcp(127.0.0.1:3306)/sql_test"
// 连接数据库
db, err = sql.Open("mysql", dsn) // 不会校验用户名和密码是否正确
if err != nil { // dsn格式不正确的时候会报错
return
}
err = db.Ping() // 尝试连接数据库
if err != nil {
return
}
db.SetMaxOpenConns(10) // 设置数据库连接池的最大连接数(连接池中只有10个连接,如果全部被占用,再来请求就会阻塞住)
db.SetMaxIdleConns(5) // 设置最大空闲连接数
return
} type user struct {
id int
name string
age int
} // 查询单个记录
func queryOne(id int) {
var u1 user //用来接收查询结果
// 1. 写查询单条记录的sql语句
sqlStr := `select id, name, age from user where id=?;` //?占位 下面的id
// 2. 执行并拿到结果
// 必须对rowObj对象调用Scan方法,因为该方法会释放数据库链接 // 从连接池里拿一个连接出来去数据库查询单条记录
db.QueryRow(sqlStr, id).Scan(&u1.id, &u1.name, &u1.age) //&u1.id, &u1.name, &u1.age初始化u1结构体对象(变量)
//row一行 // 打印结果
fmt.Printf("u1:%#v\n", u1)
} // 查询多条
func queryMore(n int) {
// 1. SQL语句
sqlStr := `select id, name, age from user where id > ?;`
// 2. 执行
rows, err := db.Query(sqlStr, n)
if err != nil {
fmt.Printf("exec %s query failed, err:%v\n", sqlStr, err)
return
}
// 3. 一定要关闭rows,才会释放连接(数据库的连接)
defer rows.Close()
// 4. 循环取值
for rows.Next() {
var u1 user
err := rows.Scan(&u1.id, &u1.name, &u1.age)
if err != nil {
fmt.Printf("scan failed,err:%v\n", err)
}
fmt.Printf("u1:%#v\n", u1)
}
} // 插入数据
func insert() {
// 1. 写SQL语句
sqlStr := `insert into user(name, age) values("图朝阳", 28)`
// 2. exec
ret, err := db.Exec(sqlStr) //exec执行(Python中的exec就是执行字符串代码的,返回值是None,eval有返回值)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
return
}
// 如果是插入数据的操作,能够拿到插入数据的id
id, err := ret.LastInsertId()
if err != nil {
fmt.Printf("get id failed,err:%v\n", err)
return }
fmt.Println("id:", id)
} // 更新操作
func updateRow(newAge int, id int) {
sqlStr := `update user set age=? where id > ?`
ret, err := db.Exec(sqlStr, newAge, id)
if err != nil {
fmt.Printf("update failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() //RowsAffected 受影响的行数
if err != nil {
fmt.Printf("get id failed,err:%v\n", err)
return
}
fmt.Printf("更新了%d行数据\n", n)
} // 删除
func deleteRow(id int) {
sqlStr := `delete from user where id=?`
ret, err := db.Exec(sqlStr, id)
if err != nil {
fmt.Printf("delete failed,err:%v\n", err)
return
}
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("get id failed,err:%v\n", err)
return
}
fmt.Printf("删除了%d行数据\n", n)
} // 预处理方式插入多条数据
func prepareInsert() {
sqlStr := `insert into user(name, age) values(?,?)`
stmt, err := db.Prepare(sqlStr) // 1.把SQL语句先发给MySQL预处理一下
if err != nil {
fmt.Printf("prepare failed ,err:%v\n", err)
return
}
defer stmt.Close()
// 后续只需要拿到stmt去执行一些操作
var m = map[string]int{
"六七强": 30,
"王相机": 32,
"天说": 72,
"白慧姐": 40,
}
for k, v := range m {
stmt.Exec(k, v) // 2.后续只需要传值
}
} func main() {
err := initDB()
if err != nil {
fmt.Printf("init DB failed, err:%v\n", err)
}
fmt.Println("连接数据库成功!")
// queryOne(2)
// queryMore(2)
// insert()
// updateRow(9000, 2)
// deleteRow(2)
prepareInsert()
}
Go实现MySQL事务
什么是事务?
事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元),同时这个完整的业务需要执行多次的DML(insert、update、delete)语句共同联合完成。A转账给B,这里面就需要执行两次update操作。
在MySQL中只有使用了Innodb
数据库引擎的数据库或表才支持事务。事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行。
事务的ACID
通常事务必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
条件 | 解释 |
---|---|
原子性 | 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 |
一致性 | 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 |
隔离性 | 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。 |
持久性 | 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 |
事务相关方法
Go语言中使用以下三个方法实现MySQL中的事务操作。 开始事务
func (db *DB) Begin() (*Tx, error)
提交事务
func (tx *Tx) Commit() error
回滚事务
func (tx *Tx) Rollback() error
代码:
package main import (
"database/sql"
"fmt" _ "github.com/go-sql-driver/mysql" // init()
) var db *sql.DB // 是一个连接池对象 func initDB() (err error) {
// 数据库信息
// 用户名:密码@tcp(ip:端口)/数据库的名字
dsn := "root:root@tcp(127.0.0.1:3306)/sql_test"
// 连接数据库
db, err = sql.Open("mysql", dsn) // 不会校验用户名和密码是否正确
if err != nil { // dsn格式不正确的时候会报错
return
}
err = db.Ping() // 尝试连接数据库
if err != nil {
return
}
db.SetMaxOpenConns(10) // 设置数据库连接池的最大连接数
db.SetMaxIdleConns(5) // 设置最大空闲连接数
return
} type user struct {
id int
name string
age int
} func transactionDemo() {
// 1. 开启事务
tx, err := db.Begin()
if err != nil {
fmt.Printf("begin failed,err:%v\n", err)
return
}
// 执行多个SQL操作
sqlStr1 := `update user set age=age-2 where id=1`
sqlStr2 := `update xxx set age=age+2 where id=2`
// 执行SQL1
_, err = tx.Exec(sqlStr1)
if err != nil {
// 要回滚
tx.Rollback()
fmt.Println("执行SQL1出错啦,要回滚!")
return
}
// 执行SQL2
_, err = tx.Exec(sqlStr2)
if err != nil {
// 要回滚
tx.Rollback()
fmt.Println("执行SQL2出错啦,要回滚!")
return
}
// 上面两步SQL都执行成功,就提交本次事务
err = tx.Commit()
if err != nil {
// 要回滚
tx.Rollback()
fmt.Println("提交出错啦,要回滚!")
return
}
fmt.Println("事务执行成功!")
} func main() {
err := initDB()
if err != nil {
fmt.Printf("init DB failed, err:%v\n", err)
}
fmt.Println("连接数据库成功!")
transactionDemo()
}
Go_MySQL查询插入删除的更多相关文章
- 手把手教你使用C#操作SQLite数据库,新建数据库,创建表,插入,查询,删除,运算符,like
目录: 一.新建项目,添加引用 二.创建数据库 三.创建表 四.插入数据 五.查询数据 六.删除数据 七.运算符 八.like语句 我的环境配置:windows 64,VS,SQLite(点击下 ...
- Hibernate插入、查询、删除操作 HQL
Hibernate的所有的操作都是通过Session完成的. 基本步骤如下: 1:通过配置文件得到SessionFactory: SessionFactory sessionFactory=new C ...
- Splay的基本操作(插入/删除,查询)
Splay的基本操作(插入/删除,查询) 概述 这是一棵二叉查找树 让频繁访问的节点尽量靠近根 将查询,插入等操作的点"旋转"至根 树的高度均摊为$log_n$ 变量 int ro ...
- TODO:MongoDB的查询更新删除总结
TODO:MongoDB的查询更新删除总结 常用查询,条件操作符查询,< .<=.>.>=.!= 对应 MongoDB的查询操作符是$lt.$lte.$gt.$gte.$ne ...
- oracle_SQL 实验查询及删除重复记录 依据条件 (row)
除数据库表中的重复记录 根据条件 ① 创建表准备数据 创建表 tab_test -- Create table create table TAB_TEST ( ID NUMBER, NAME NVAR ...
- 64、django之模型层(model)--建表、查询、删除基础
要说一个项目最重要的部分是什么那铁定数据了,也就是数据库,这篇就开始带大家走进django关于模型层model的使用,model主要就是操纵数据库不使用sql语句的情况下完成数据库的增删改查.本篇仅带 ...
- django之模型层(model)--建表、查询、删除基础
要说一个项目最重要的部分是什么那铁定数据了,也就是数据库,这篇就开始带大家走进django关于模型层model的使用,model主要就是操纵数据库不使用sql语句的情况下完成数据库的增删改查.本篇仅带 ...
- python Trie树和双数组TRIE树的实现. 拥有3个功能:插入,删除,给前缀智能找到所有能匹配的单词
#coding=utf- #字典嵌套牛逼,别人写的,这样每一层非常多的东西,搜索就快了,树高26.所以整体搜索一个不关多大的单词表 #还是O(). ''' Python 字典 setdefault() ...
- [LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复
Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...
随机推荐
- wxPython学习笔记
------------恢复内容开始------------ 学习wxPython 资料 1.wxpython wiki Getting started with wxPython https://w ...
- sublime text 3安装html-css-js prettify后使用时报错An unhandled OS error was encountered
我在安装代码格式整理插件 html-css-js prettify 后,在使用时弹出报错提示如下图 意思大概是node.js什么路径没配置对,对于开始下载sublime text 3使用到各种插件的安 ...
- 2019.2.21 T2题解
meet 大概思路就是 , 找出相交的路径 , 判断方向 , 分类讨论.. 假设已经找出了相交路径 ... 若方向相同 , 则找到相交路径上边权的最大值 , 若最大值>出发时间差 , 则可行. ...
- POJ 1099 Square Ice 连蒙带猜+根据样例找规律
目录 题面 思路 思路 AC代码 题面 Square Ice Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4526 A ...
- gulp-css-spriter 雪碧图合并
相信做前端的同学都做过这样的事情,为优化图片,减少请求会把拿到切好的图标图片,通过ps(或者其他工具)把图片合并到一张图里面,再通过css定位把对于的样式写出来引用的html里面.gulp-css-s ...
- Wannafly Camp 2020 Day 1F 乘法 - 字符串
一开始想根据单调性双指针 后来血了才想起来负负得正 于是暴力二分答案即可 #include <bits/stdc++.h> using namespace std; #define int ...
- linux - python:卸载
[root@test ~]# rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps ##强制删除已安装程序及其关联[root@test ~]# ...
- SpringBoot学习- 9、Slf4j日志
SpringBoot学习足迹 在上一篇学习中 通过画红线的注解,可以直接在下面log.debug输出日志到控制台,但是写日志文件就没那么顺利了,一直不成功,找了N种配置,以下配置方法可行 首先确保已引 ...
- c++ 踩坑大法好 复合数据类型------vector
1,vector是啥? 是具有动态大小的数组,具有顺序.能够存放各种类型的对象.相比于固定长度的数组,运行效率稍微低一些,不过很方便. 2,咋用? 声明: vector <int> vi; ...
- 详解C/C++中的的:#pragma pack(push) 、#pragma pack(pop) 和#pragma pack()
前言 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定. 但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢? ...