Golang-MySQL

一.MySQl

1 MySQl安装

ubuntu:依次输入指令
1.sudo apt-get update
2.sudo apt-install mysql-server

验证是否成功:
systemctl status mysql:
"Active:active(running)"则安装成功

2MySQL 卸载命令

sudo apt pure mysql-*
sudo rm -rf /etc/mysql/ /var/lib/mysql
sudo apt autoremove
sudo apt autoclean

3 登录MySQL

1.以root用户登录
sudo mysql -u root -p (-u 指定用户名 -p需要输入密码)
或:sudo mysql

2.ubuntu安装MySQL时,会自动产生一个帐号debian-sys-maint,可以通过cat /etc/mysql/debain.cnf查看该账户的密码
.
Mysql 设置root用户不需密码登入

4 MySQL指令

查看命令:
1查看有哪些数据库:show databases;
2显示数据库中的表信息:show tables from 数据库名;
3查看某个表中的某些属性:select Filed1, Filed2... from 数据库名.表名,例如:select User,Host from mysql.user;\ select * from mysql.user:查看user表的所有字段。
4查看表的结构:desc 表名

5 in /between关键字:

 #in的使用
SELECT *
FROM customers
WHERE state not in ('VA','FL','GA');
 #between 关键字 闭区间形式
SELECT *
FROM customers
WHERE points BETWEEN 1000 AND 3000;

6and / or 逻辑字符:

#多项过滤条件组合 and or 优先级:and 大于 or 故先查询满足and 后 or
SELECT *
FROM customers 
WHERE birth_date > '1990-01-01' or
 ( points>1000 and state ='VA');

7反向查找:

 SELECT *
 FROM customers
 #等价于 where birth_date <= '1990-01-01' and points <= 1000
 WHERE NOT (birth_date > '1990-01-01' or points>1000);

8 like关键字
类似正则表达,sql语句中,%表示任何数量的字符,%b:以b结尾内容,b%:以b开头的内容,%b%:内容中含有b单词(mysql中不区分大小写);

_:表示单个字符,like _____y表示前5个单词任意最后的单词为y

SELECT *
FROM customers
WHERE last_name LIKE 'b%';

在这里插入图片描述

SELECT *
FROM customers
WHERE last_name LIKE '_____y';

在这里插入图片描述

9 regexp:(regular express)正则表达,类似Linux系统中的操作符,^表示:头部,$表示尾部,|表示逻辑或,[?- ?]?表示匹配符;
操作案例:
where last_name regexp 'field' :过滤出last_name中含有’field’的row。
where last_name regexp '^field':过滤出last_name中以’field’开头的row。
where last_name regexp 'field$':过滤出last_name中以’field’结尾的row。
where last_name regexp 'field|mac':过滤出last_name中含有’field’或者含有mac字段的row。
where last_name regexp '[abc]o'等价于where last_name regexp '[a-c]o':过滤出last_name中含有’ao’或’bo’或’co’字段的row。

10 查找空/数据遗失的row:is null
where phone_number is null

11 排序order by
默认为升序,
降序:desc

#排序 降序desc(decline)
SELECT *
FROM customers
order by first_name desc;

在这里插入图片描述
order by 也可按多种要求排序:
#按多种属性排序,例如在先按州升序排序,相同州的按姓降序排序

SELECT *
FROM customers 
order by state, first_name desc;

在这里插入图片描述

12 limit:限制作用
查看分数最高的三名客户

SELECT * 
FROM customers
ORDER BY points DESC
LIMIT 3;

跳过表中前面6行数据,取随后的3行数据

SELECT * 
FROM customers	
LIMIT6,3;

limit的顺序很重要:在whereorder by 等后面。

13join连接
jion 关键字: 将多个表通过共同属性连接在一起,构成一个信息更完善的独立表。

基本操作
join可分为内部连接inner join和外部连接outer joins
一般表之间的内部连接inner join可简写为join
表的outer joins有:保持左表全数据合并的left outer join(简写为left join),以及保持右表全数据合并的right outer join(简写为right join)

SELECT * 
FROM orders
JOIN customers 
	ON orders.customer_id = customers.customer_id;

#加以细化
#需注意对于用于连接的属性需要定义清使用的是哪个表的数据,否则会提示属性列表模糊

SELECT order_id,orders.customer_id,first_name,last_name 
FROM orders
JOIN customers 
	ON orders.customer_id = customers.customer_id;

为了便于管理和编程,在编程中对表明取别名;但需注意:使用别名后的整个模块中都要使用别名。

SELECT order_id,order_date, o.customer_id,first_name,last_name 
FROM orders o
JOIN customers c
	ON o.customer_id = c.customer_id;

self join表的自连接:一个表自身连接自己。
表的自连接查找公司员工中的管理层时特别有效:

SELECT 
	e.employee_id,
    e.first_name,
    m.first_name AS manager
FROM employees e
JOIN employees m 
	ON e.reports_to = m.employee_id;

#查找经理
SELECT 
	distinct m.first_name AS manager ,
    m.employee_id,
    m.job_title
FROM employees e
JOIN employees m 
	ON e.reports_to = m.employee_id;

#查找员工
SELECT 
	distinct e.first_name AS employees ,
    e.employee_id,
    e.job_title
FROM employees e
JOIN employees m 
	ON e.reports_to = m.employee_id;

连接两个表以上

#表连接多个表
USE sql_store;
SELECT 
	o.order_id,
    o.order_date,
    o.customer_id,
    c.first_name,
    c.phone,
    c.address,
    os.name AS statu
FROM orders o 
JOIN customers c 
	ON o.customer_id = c.customer_id
JOIN order_statuses os
	ON o.status = os.order_status_id ;

隐式连接语法(implicit join syntax):
不推荐,如果忘了添加where条件,就为cross join的隐式表达,会得到一个交叉复合的文件。
具体使用方法如下:

SELECT *
FROM orders o
JOIN customers c
	ON  o.customer_id = c.customer_id;
#implicit join syntax
SELECT *
FROM orders o, customers c 
WHERE o.customer_id = c.customer_id;

交叉连接cross joins
用于将各表中的属性都需一一配对的情况,例如商品的名称、各种颜色、各种尺寸大小的信息整合时。

SELECT *
FROM  order_items oi
CROSS JOIN products p; 

#隐式表达
SELECT *
FROM  order_items oi, products p; 

所以当cross join的隐式表达加上where过滤时即为join的隐式表达。

outer joins外连接:

(1)外连接即是将某个表完整信息直接连接起。

#外连接 outer join
#右连接  将customers表整体连接
SELECT 
	o.order_id,
    c.customer_id,
    c.first_name
FROM orders o
RIGHT JOIN customers c
	ON o.customer_id = c.customer_id;

#左连接  将customers表整体连接
SELECT 
	o.order_id,
    c.customer_id,
    c.first_name
FROM customers c
LEFT JOIN orders o
	ON o.customer_id = c.customer_id;

(2)多个表格间的外连接
应避免左右连接的混合使用,建议统一使用LEFT JOIN

#应避免左右连接的混合使用,建议统一使用LEFT JOIN
SELECT 
	c.customer_id,
	c.first_name,
    o.order_id,
    sh.name AS shipper
FROM customers c
LEFT JOIN orders o
	ON c.customer_id = o.customer_id
LEFT JOIN shippers sh
	ON o.shipper_id = sh.shipper_id
ORDER BY c.customer_id;

14 using关键字:
在连接表时,当属性名在多个表中一模一样时,可以使用using简化匹配条件写法

SELECT *
FROM order_items oi
JOIN order_item_notes oin
	USING(order_id,product_id);
    
SELECT 
	o.order_id,
    o.order_date,
    c.first_name AS customer, 
    os.name AS status,
    sh.name AS shipper
FROM orders o
JOIN customers c
	USING(customer_id)
LEFT JOIN shippers sh 
	USING(shipper_id)
JOIN order_statuses os
	ON	o.status = os.order_status_id;

15 union联合
可以将不同的查询结果合并成一个查询集合;
UNION [ALL | DISTINCT]
DISTINCT: 可选,删除结果集中重复的数据。默认情况下 UNION 操作符已经删除了重复数据,所以 DISTINCT 修饰符对结果没啥影响。
ALL: 可选,返回所有结果集,包含重复数据。
(1)union 将同一个表的不同查询结果生成为一个查询集合

SELECT	
	order_id,
    order_date ,
    'Active' AS status
FROM orders O
WHERE O.order_date > '2019-01-01'
UNION
SELECT	
	order_id,
    order_date ,
    'Archived' AS status
FROM orders O
WHERE O.order_date < '2019-01-01';

(2)union 将不同表的不同查询结果生成为一个查询集合
各表查询返回的结果(属性/列)数量要一致,否则无法进行合并

SELECT
	customer_id,
	first_name,
    points,
    'Bronze' AS type
FROM customers
WHERE points < 2000
UNION
SELECT 
	customer_id,
	first_name,
    points,
    'Siliver' AS type
FROM customers
WHERE points BETWEEN 2000 AND 3000
UNION
SELECT 
	customer_id,
	first_name,
    points,
    'Gold' AS type
FROM customers
WHERE points > 3000
ORDER BY first_name;

创建命令:
1创建数据库:create database 数据库名;使用该数据库use 数据库名

2创建表:create table 表名 (属性1 类型,属性2 类型);
例如:create table user_tb1 (id integer primary key auto_increment,username varchar(20),password varchar(20));

3复制表中的数据/对表中数据进行存档
整个表格复制存档:

#创建存档文件
CREATE TABLE orders_archived AS 
#子查询语句
SELECT * FROM orders;  

需注意的是所创建的存档表orders_archived 中的内容与orders表中一样,但是orders_archived中的主键、键值自动增加等功能不保留orders中的设置。

内容选择性存档:
第一种:已有存档表,进行内容更新

#对原先存档内容进行截断【可选】
TRUNCATE orders_archived;
#往存档中添加内容
INSERT INTO orders_archived 
SELECT * 
FROM orders
WHERE order_date < '2019-01-01';

第二种:直接创建新的存档表

CREATE TABLE orders_archived1 AS 
SELECT * FROM orders WHERE order_date < '2019-01-01' ;  

修改命令
插入数据:
1在表中插入数据:insert into 表名 (属性1,属性2...) values(值1,值2...);

#1 插入方式,所有属性都插入
INSERT INTO customers VALUES(
	DEFAULT,
	'John',
	'Smith',
	'1990-08-07',
	NULL,
    'hubeiwuhan',
    'wuhan',
    'hubei',
    DEFAULT);
    
#2 插入方式二
INSERT INTO customers (
	first_name,
    last_naem,
    birth_date,
    address,
    city,
    state)
VALUES(
	'Jarry',
	'Helon',
	'1992-08-77',
    'hubeiwuhan',
    'wuhan',
    'hubei');

2同时插入多行数据

INSERT INTO `shippers` (`name`) 
VALUES ('shipper1') , ('shipper2'),('shipper3');

 #exercise:
 INSERT INTO `products` (
	`name`,
	`quantity_in_stock`,
	`unit_price`)
 VALUES ('Product1',10,1.95),
		 ('Product2',11,1.25),
		 ('Product2',12,1.65);

3 插入分层的/阶级式的多行
使用到last_insert_id()内置函数,返回上一次插入的id值(主键值)。

  INSERT INTO `orders` (`customer_id`,`order_date`)
  VALUES (1,'2020-09-08');
INSERT INTO `order_items` 
VALUES (LAST_INSERT_ID(),4,15,10.1),
	   (LAST_INSERT_ID(),3,10,7.1);

数据更新:
更新数据:update 表名 set 属性1=?,属性2=? where id=?
例如:update user_tb1 set username=lisa,password=lisa111 where id =1;

1普通更新:

#更新一行数据:
UPDATE invoices
SET 
	payment_total = invoice_total * 0.5,
    payment_date = due_date
WHERE invoice_id = 3;
#更新多行数据
WHERE client_id in (3,4)

2带有子查询的更新方法:


UPDATE invoices
SET 
	payment_total = invoice_total * 0.5,
    payment_date = due_date
WHERE client_id = 
		(SELECT client_id
			FROM clients
			WHERE name = 'Myworks' );

UPDATE invoices
SET 
	payment_total = invoice_total * 0.5,
    payment_date = due_date
WHERE client_id in 
		(SELECT client_id
			FROM clients
			WHERE state in ('CA','NY') );

在现有表中增加一行新的列

alter table  <tableName> add colum <fieldName> <int/类型> 

删除命令
1.删除某一行:delete from 表名 where id=?;
例如:delete from user_tb1 where id=5;删除id=5的行内容
2.带条件判断,范围删除delete from 表名 where id>?;
delete from user_tb1 where id>4;删除满足id>4条件的所有行内容
3带子查询的删除

DELETE FROM invoices
WHERE clinet_id = 
		(SELECT * 
		  FROM clients
		  WHERE name = 'Myworks');

4.删除数据库

drop database <数据库名>

5.删除表

drop table <表名>

5. MySql事务

1)原子性(Atomicity):
全部成功或全部失败,不存在一方成功一方失败的现象.
例如A,B帐号之间转账情景,A 转给B,A帐号的金额要减少,同时B 帐号的金额要增加.

原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

2)一致性(Consistency)
假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

3)隔离性(Isolation)
两个事务同时进行,不会相互影响.
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

4)持久性
数据写入磁盘

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

二. Golang操控MySQl

1 下载依赖

Go的database/sql包提供了保证SQL或类SQL数据库的泛用接口,并不提供具体的数据库驱动。使用database/sql包时必须注入(至少)一个数据库驱动(例如:MySQL)。

go get -u github.com/go-sql-driver/mysql
(需确保电脑下载了个git,及系统PATH包含有git环境)
(1)通过which git可以查看git的路径,再通过echo $PATH查看系统路径中是否包含了git的路径。
(2)在ubuntu系统中下载依赖时,要在含有go mod包的路径下载,否则下载依赖时可能会报错。
(3)确保在$GOPATH的路径下src文件下的github.com文件中有go-sql-driver文件

2 golang 操作mysql指令

1.连接mysql

package main

import (
	"database/sql"
	"fmt"
	"time"

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

func main() {
    
    
	db, err := sql.Open("mysql", "root:xxxx(密码)@/go_db")
	if err != nil {
    
    
		panic(err)
	}
	fmt.Println(db)

	// 最大连接时长
	db.SetConnMaxLifetime(time.Minute * 3)
	// 最大连接数
	db.SetMaxOpenConns(10)
	// 空闲连接数
	db.SetMaxIdleConns(10)
}
package main

import (
	"database/sql"
	"fmt"

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

// 定义一个全局对象db
var db *sql.DB

func initDB() (err error) {
    
    
	dsn := "root:@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"

	//sql.Open不会检验密码是否正确
	db, err = sql.Open("mysql", dsn)
	if err != nil {
    
    
		return err
	}
	// 尝试与数据库建立连接(校验dsn是否正确)
	err = db.Ping()
	if err != nil {
    
    
		return err
	}
	return nil

}

func main() {
    
    
	err := initDB() //调用初始化数据库的函数
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	} else {
    
    
		fmt.Println("连接成功")
	}
	/*
		// 最大连接时长
		db.SetConnMaxLifetime(time.Minute * 3)
		// 最大连接数
		db.SetMaxOpenConns(10)
		// 空闲连接数
		db.SetMaxIdleConns(10)
	*/
}


2.查询

package main

import (
	"database/sql"
	"fmt"

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

// 定义一个全局对象db
var db *sql.DB

type User struct {
    
    
	id       int
	username string
	password string
}

func initDB() (err error) {
    
    
	dsn := "root:@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"

	//sql.Open不会检验密码是否正确
	db, err = sql.Open("mysql", dsn)
	if err != nil {
    
    
		return err
	}
	// 尝试与数据库建立连接(校验dsn是否正确)
	err = db.Ping()
	if err != nil {
    
    
		return err
	}
	return nil

}

//单行查询db.QueryRow()执行一次查询,并期望返回最多一行结果(即Row)
// Qury.Row总是返回非nil值,直到返回值的Scan方法被调用时,才会返回被延迟的错误。
func queryOneRow(id int) {
    
    
	s := "select * from user_tb1 where id = ?"
	var u User
	err := db.QueryRow(s, id).Scan(&u.id, &u.username, &u.password)
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	} else {
    
    
		fmt.Printf("u:%v\n", u)
	}
}

// 多行查询db.Query(),执行一次返回多行结果(即多行Rows)一般用于执行select命令。
// 参数args表示query中的占位参数
func queryManyRow() {
    
    
	s := "select * from user_tb1"
	r, err := db.Query(s)
	var u User
	defer r.Close() //***
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	} else {
    
    
		for r.Next() {
    
    
			r.Scan(&u.id, &u.username, &u.password)
			fmt.Printf("user:%v\n", u)
		}
	}

}

func queryManyRow1() {
    
    
	s := "select id , username, password from user_tb1 where id > ?"
	rst, err := db.Query(s, 0)
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	}
	var u User
	defer rst.Close()
	for rst.Next() {
    
    
		err = rst.Scan(&u.id, &u.username, &u.password)
		if err != nil {
    
    
			fmt.Printf("err:%v\n", err)
			continue
		}
		fmt.Printf("u:%v\n", u)

	}
}

func main() {
    
    
	err := initDB() //调用初始化数据库的函数
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	} else {
    
    
		fmt.Println("连接成功")
	}
	queryOneRow(2)

	queryManyRow()

	queryManyRow1()
}



插入、更新和删除操作都使用db.Exec()方法
func (db *sql.DB) Exec(query string, args ...interface{) (sql.Result,error)

3.插入

package main

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

//插入、更新和删除操作都使用Exec方法。
// z定义一个全局对象db
var db *sql.DB

func initDB() (err error) {
    
    
	dsn := "root:@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"

	//sql.Open不会检验密码是否正确
	db, err = sql.Open("mysql", dsn)
	if err != nil {
    
    
		return err
	}
	// 尝试与数据库建立连接(校验dsn是否正确)
	err = db.Ping()
	if err != nil {
    
    
		return err
	}
	return nil

}

func insertData(username, password string) {
    
    
	dsn := "insert into user_tb1 (username,password) values (? ,?)"
	ret, err := db.Exec(dsn, username, password) //username 不能是汉字? utf-8转化问题?
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
		return
	}

	theID, err := ret.LastInsertId() //新插入数据的id
	if err != nil {
    
    
		fmt.Printf("get lastinsert Id failed,err :%v\n", err)
		return
	}
	fmt.Printf("insert success,the id is %d\n", theID)
}

func main() {
    
    
	err := initDB() //调用初始化数据库的函数
	if err != nil {
    
    
		fmt.Printf("err:%v\n", err)
	} else {
    
    
		fmt.Println("连接成功")
	}
	
	insertData("lisi", "lisi123")
}

4.修改/更新:

func updaDate(username, password string, id int) {
    
    
	dsn := " update user_tb1 set username=?,password=? where id =?"
	ret, err := db.Exec(dsn, username, password, id)
	if err != nil {
    
    
		fmt.Printf("执行更新失败,err:%v\n", err)
		return
	}
	rows, err := ret.RowsAffected()
	if err != nil {
    
    
		fmt.Printf("更新失败,err:%v\n", err)
		return
	}
	fmt.Printf("更新成功,更新的行数:%d\n", rows)
}

5.删除:


func delData(id int) {
    
    
	dsn := " delete from user_tb1 where id =?"
	// dsn := "delete from user_tb1 where id >?" //删除多行
	ret, err := db.Exec(dsn, id)
	if err != nil {
    
    
		fmt.Printf("执行删除失败,err:%v\n", err)
		return
	}
	rows, err := ret.RowsAffected()
	if err != nil {
    
    
		fmt.Printf("删除失败,err:%v\n", err)
		return
	}
	fmt.Printf("删除成功,删除的行数:%d\n", rows)
}

3.go-Mysql事务

1)import (“github.com/jmoiron/sqlx”)
对(“github.com/go-sql-driver/mysql”)库进行了进一步封装的第三方库.
例如:

package main

import (
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

type Person struct {
    
    
	UserId   int    `db:"user_id"`
	Username string `db:"username"`
	Sex      string `db:"sex"`
	Email    string `db:"email"`
}

type Place struct {
    
    
	Country string `db:"country"`
	City    string `db:"city"`
	TelCode int    `db:"telcode"`
}

var Db *sqlx.DB

func init() {
    
    

	database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/go_db")
	if err != nil {
    
    
		fmt.Println("open mysql failed,", err)
		return
	}

	Db = database
}

func main() {
    
    

	_, err := Db.Exec("update person set username=? where user_id=?", "stu0003", 1)
	if err != nil {
    
    
		fmt.Println("exec failed, ", err)
		return
	}

}

2)Db.Begin()开始事物
返回链接,进行insert\update等操作

3)Db.Commit()提交事务
返回没有错误即可以提交

4)Db.Rollback()回滚事物
返回有错误,回滚到错误前

func main() {
    
    
	// 开启事务
	conn, err := Db.Begin()
	if err != nil {
    
    
		fmt.Println("conn failed, ", err)
		return
	}

	r, err := conn.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu101", "man", "[email protected]")
	if err != nil {
    
    
		fmt.Println("exec failed, ", err)
		// 事务出错,滚动回归到错误前
		conn.Rollback()
		return
	}
	id, err := r.LastInsertId()
	if err != nil {
    
    
		fmt.Println("exec failed, ", err)
		return
	}

	_, err = conn.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu010", "man", "[email protected]")
	if err != nil {
    
    
		fmt.Println("exec failed, ", err)
		// 事务出错,滚动回归到错误前
		conn.Rollback()
		return
	}

	fmt.Println("insert succ:", id)
	//执行成功,提交事务,落盘
	conn.Commit()

}

猜你喜欢

转载自blog.csdn.net/ALEX_CYL/article/details/124907420
今日推荐