go-操作mysql数据库go-操作mysql数据库

1.mysql原始命令

a.登录

登录:
mysql -u root -p密码  //连本机的

SELECT User, Host, Password FROM mysql.user;  //查看用户

添加新用户:
create user 'liuxuan14'@'localhost' identified by '123456';
修改密码:
set password for 'liuxuan14'@'localhost'=password('1998');
为用户授权:
//允许访问所有数据库下的所有表
grant all privileges on *.* to '新用户名'@'指定ip' identified by '新用户密码' ;
//指定数据库下的指定表
grant all privileges on test.test to '新用户名'@'指定ip' identified by '新用户密码' ;
//只拥有查询权限
grant select on *.* to '新用户名'@'指定ip' identified by '新用户密码' WITH GRANT OPTION;
FLUSH PRIVILEGES;  //刷新权限

删除用户:
drop user liuxuan@localhost;

连接远程数据库:
MySQL 连接远程数据库(192.168.5.116),端口“3306”,用户名为“root”,密码“123456”
mysql -h 192.168.5.116 -P 3306 -u root -p123456
mysql -h ip -P 端口 -A -u name  -p 密码

create database name

b.建表

CREATE TABLE IF NOT EXISTS `mytable`(
   `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '自增',
   `app_id` bigint NOT NULL DEFAULT '0' COMMENT '应用id',
   `time` int NOT NULL DEFAULT '0' COMMENT '时间',
   `date` DATE,
   PRIMARY KEY ( `id` )
   UNIQUE KEY `idx_app` (`app_id`) USING BTREE
   KEY `idx_ip` (`machine_ip`) USING BTREE,
   KEY `idx_app_machineid` (`app_id`,`machine_id`) USING BTREE
)ENGINE=InnoDB DEFAULT COMMENT='表名';

AUTO_INCREMENT定义列为自增的属性,一般用于主键,数值会自动加1。
PRIMARY KEY关键字用于定义列为主键。 您可以使用多列来定义主键,列间以逗号分隔。
ENGINE 设置存储引擎,CHARSET 设置编码。

表结构:desc name;
建表语句:show create tablename;

注释

注释:comment
create table test1 ( 
    field_name int comment '字段的注释' 
)comment='表的注释';
修改表的注释:
alter table test1 comment '修改后的表的注释';
修改字段的注释:
alter table test1 modify column field_name int comment '修改后的字段注释'; 
查看表注释:
show  create  table  test1; 
查看字段注释:
show  full  columns  from  test1; 

索引

唯一索引:
UNIQUE KEY
1  主键是一种约束,唯一索引是一种索引,两者在本质上是不同的。
2  主键创建后一定包含一个唯一性索引,唯一性索引不一定就是主键。
3   唯一性索引列允许空值, 而主键列不允许为空值。
4   主键可以被其他表引用为外键,而唯一索引不能。
5   一个表最多只能创建一个主键,但是可以创建多个唯一索引。
6   主键更适合那些不容易改变的唯一标识,如自动递增列,身份证号等。
7   在RBO 模式下,主键的执行计划优先级高于唯一索引。两者可以提高查询的速度。

c.添加一个字段

alter table tablename add `app_name` varchar(16) NOT NULL DEFAULT '';

d.修改数据

update tablename set 字段='修改的值' where 条件;
多个字段中间加,

e.删除

删库:drop database name;
删表:drop table name;

mysql删除一行:
delete from 表 where 条件;

f.添加一行

insert into tablename (app_id,machine_id,machine_ip,ctime,use_perc) values(?,?,?,?,?);   //对应字段加

insert into 表名 values(int,'string')(..);  //可一次性加多行,一行全部数都有

insert into 表名 set 列名='', ...;

2.go操作数据库

使用:database/sql包

mysql默认端口号3306

查看:mysql内,show global variables like 'port';

查看mysql配置文件目录:

mysql --help|grep 'my.cnf'

a.创建连接池

//1.创建连接池
func newPool() *sql.DB {  //sql.DB 表示一个连接池
	cfg := mysql.NewConfig()
	cfg.User = "name"
	cfg.Passwd = "123456"
	cfg.Net = "tcp"
	cfg.Addr = "127.0.0.1:3306"
	cfg.DBName = "mydb"
	dsn := cfg.FormatDSN()

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal(err)
	}
	if err := db.Ping(); err != nil { //ping测试网络连通性及用户密码是否正确
		log.Fatal(err)
	}
	return db
}

b.query查询

func QueryUser(id int64) (*User, error) {
  var db = newPool()  //创建连接
	rows, err := db.Query("select `id`, `name` from `users` where `id` = ?", id)
	if err != nil {
		return nil, err
	}
	defer rows.Close() // 注意这里,一定要关闭
	user := User{}
	for rows.Next() {
		if err := rows.Scan(&user.ID, &user.Name); err != nil {
			return nil, err
		}
		break
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return &user, nil
}

连接池对程序员是透明的,这里并不需要显式的从连接池里获取连接,而是通过连接池来执行查询语句。
Query 方法返回一个 *Rows 指针,代表结果集。

要注意的是 defer rows.Close() 如果忘了关闭,可能会造成连接泄露。

rows.Scan 方法有个方便的特性,如果id在数据库里是 varchar(50) 类型,我们传的参数&user.ID指向int64,这依然可以工作,Scan 方法会执行自动转换。

c.单行查询queryrow

// QueryUser1 单行查询
func QueryUser1(id int64) (*User, error) {
	row := pool.QueryRow("select `id`, `name` from `users` where `id` = ?", id)
	user := User{}
	if err := row.Scan(&user.ID, &user.Name); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil  // 返回 (*User)(nil) 表示查询结果不错在
		}
		return nil, err
	}
	return &user, nil
}

d.插入更新删除exec

// InsertUser 插入用户
func InsertUser(name string) (int64, error) {
	res, err := pool.Exec("insert into `users` (`name`) values (?)", name)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}
// UpdateUser 更新用户
func UpdateUser(id int64, name string) error {
	_, err := pool.Exec("update `users` set `name` = ? where `id` = ?", name, id)
	if err != nil {
		return err
	}
	return nil
}
// DeleteUser 删除用户
func DeleteUser(id int64) error {
	_, err := pool.Exec("delete from `users` where `id` = ?", id)
	if err != nil {
		return err
	}
	return nil
}

e.事务

// UpdateFooBar 更新
func UpdateFooBar(id int64, x, y string) (err error) {
	tx, err := pool.Begin()
	if err != nil {
		return
	}
	defer func() {
		switch {
		case err != nil:
			tx.Rollback()
		default:
			err = tx.Commit()
		}
	}()

	_, err = tx.Exec("update `foo` set `x` = ? where `id` = ?", x, id)
	if err != nil {
		return
	}
	_, err = tx.Exec("update `bar` set `y` = ? where `id` = ?", y, id)
	if err != nil {
		return
	}

	return
}

3.mysql加锁

读锁全表锁(LOCK TABLE 表 READ)
读锁行锁(SELECT ... LOCK IN SHARE MODE)
写锁全表锁(LOCK TABLE 表 WRITE)
写锁行锁(SELECT ... FOR UPDATE)

锁总体可以分为乐观锁和悲观锁,简单说,乐观锁用版本号控制,悲观锁用锁控制。
乐观锁:核心原理是增加一个version的字段来控制。添加一个version字段,每个更新时where条件都加上它,并且也更新它UPDATE users SET name="雪山飞猪",version=version+1 WHERE id=3 AND version=0 UPDATE users SET name="chenqionghe",version=version+1 WHERE id=3 AND version=0。这就是最简单的CAS机制。
悲观锁:类似Go语言里的Mutex和RwMutex

共享锁(S锁)又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

排他锁(X锁)又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

写锁表锁:
加锁:lock table kiss_share_idproducer write;
此时其他进程无法读也无法写。
解锁:unlock table;
--------------------------------
写锁行锁:
begin;
加锁:select * from  kiss_share_idproducer where app_id=21 for update;
其他再加锁,等待,直到占锁的commit;
更新:update kiss_share_idproducer set mix_id=7 where app_id=21;
解锁:commit;
读锁表锁:
加锁:lock table kiss_share_idproducer read;
此时其他进程可以读但无法写。
解锁:unlock table;
-------------------------------
读锁行锁:
加锁:select * from  kiss_share_idproducer where app_id=21 lock in share mode;
其他再加锁,等待,直到占锁的commit;
更新:update kiss_share_idproducer set mix_id=7 where app_id=21;
解锁:commit;

参考

go的mysql操作:https://blog.csdn.net/embinux/article/details/84031620

mysql加锁:https://blog.csdn.net/weixin_33838871/article/details/113566444

上一篇:Go语言圣经 - 第5章 函数 - 5.4 错误


下一篇:Go的tcp长连接