存储和数据库|青训营笔记

39 阅读6分钟

这是我参与[第五届青训营]伴学笔记创作活动的第3天

课程笔记

  • 中间层:坚固持久化和内存友好的存储器Persistent Memory
  • [缓存]重要,贯穿整个存储体系
  • [拷贝]昂贵,尽量减少

RAID技术

  • 单机存储系统做到:高性能/高性价比/高可靠性
  • RAID 0 + 1:【取两个极端再加和】
  • 结合RAID 0和1
  • 真实空间利用率仅50%
  • 容错率强,写入带宽好

关系型&非关系数据库

  • 关系型:结构化友好,支持事务,支持复杂的查询语言
  • 关系代数:对关系作运算的抽象查询语言【交、并、笛卡尔积……】
  • SQL = 一种DSL = 方便阅读的关系代数
  • 事务:A[原子性] C[一致性] I[隔离性] D[持久性]
  • 非关系型:[半]结构化友好,[可能]支持事务,[可能]支持复杂的查询语言

存储

  • 单机存储:本地文件系统&key-value存储【RocksDB】
  • Index Node & Directory Entry
  • put(k,v) & get(k)
  • 分布式存储:分布式文件系统[HDFS] & 分布式对象存储[Ceph]

我的记录&MySQL基础

前言:

  • show create database 数据库名; //查询已存在数据库的字符集
  • show databases; //查询MYSQ有哪些数据库
  • use 数据库名; //使用数据库
  • show tables; //查询某数据库的表
  • select * from 表名; //查询表内容
  • desc 表名; //查询表结构

数据库的-增-删-改-查

——《增》——
create database if not exists 数据库名;
character set = utf-8;
——《删》——
drop database 数据库名;
——《改》——
alter database 表名
character set = utf-8;
——《查》——
show databases;

表结构-增-删-改-查

——《增》——
create table 表名 if not exists(
字段名1 数据类型 约束条件 auto_increment,【列级】
字段名2 数据类型,
primary key(字段1,字段2……))charset utf8;【表级】

①>实体完整性约束(主键、候选键、自增)
1.主键:primary key【非空、唯一】
alter table 字段名 drop primary key;	//删除主键
2.复合主键:primary key(字段1,字段2……)
3.候选键:nuique【用于外键引用】
4.自增:auto_increment【数据类型只能是(int/float),字段只能是(主键/候选键)】
auto_increment = 12;{设置初始值,默认1}

②>参照完整性约束:(外键)
{先建父表再建子表}
外键:foreign key【表与表之间建立关联】
foreign key(字段名) references 表名(字段名)

③>用户定义完整性约束:(非空、默认值、CHECK)
非空:not null
默认值:default(default '女')
CHECKcheck(score>=0 and acore<=100)
——《删》——
drop table 表名;
——《改》——
①>添加字段名:
alter table 表名 add 字段名 数据类型 after 字段名
②>修改字段名和数据类型:
alter table 表名 change 旧字段名 新字段名 新字段名数据类型
③>修改一个字段的数据类型:
alter table 表名 modify 字段名 数据类型
④>修改表的名字:
alter table 表名 rename 新的表名
⑤>表结构的复制:
create table 新表名 like 旧表名【只拷贝表结构,不拷贝表内容】
——《查》——
select * from 表名;	//查询表内容
desc 表名;	//查询表结构

表内容-增-删-改-查

——《增》——
①>不完全插入:
insert into 表名 (字段名1,字段名2…)  values(值1,值2……);
②>完全插入:
insert into 表名 values(值1,值2…,值n);
③>插入数据(纯在一样的内容,不一样的就修改)
replace into 表名 values(值1,值2……)
——《删》——
drop table 表名;
delect from 表名 where 条件
——《改》——
update 表名 set 列名1=值,列名2=值 where 条件;
——《查》——
①>查询所有字段:
select * from 表名;
②>查询指定字段:
select 字段1、字段2 from 表名;【可增加简单表达式】

》聚合函数:
①>count() [统计个数]
count(字段名)	//不统计空值
count(*)	//统计空值
②>sum()	 [求和]
sum(字段名)
③>avg[求平均数]
avg(字段名)
④>max() min()	[最大值,最小值]

》分组查询:
①>group by 
//通过name的值进行聚合
select name,sum(number) from test group by name;
②>having [筛选]
//统计test表中学号平均年龄小于19岁的id
select id,avg(age)
from test
group by id
having avg(age)<19;

》多表查询:
①>全连接查询:
select * from 表名1,表名2……;
②>内连接查询:
select * from 表名1 join 表名2 on 条件;
③>外连接查询:
左外连接(left outer joinselect * from 表名1 left outer join 表名2 on 条件;
右外连接(right outer joinselect * from 表名1 right outer join 表名2 on 条件;

---	---	---

》条件查询:
①>where[条件查询]
select 字段1、字段2…… from 表名 where 表达式{=,or,and}
②>in
where 字段 in('字段1','字段2')
③>like[模糊查询]
where 字段 like 'm%';	//以开头的字段名
where 字段 like '_o__';	//以_o__形式的字段
④>is null		【判断字段是否为空】
where 字段 is null>as[字段别名]
select 原始字段 as '显示字段' from 表名
⑥>distinct[去掉重复行]
select distinct 字段名 from 表名	//查询去掉重复信息
⑦>order by [排序]
order by id desc;	//降序排序
order by id asc;	//升序排序
⑧>limit[控制显示数据条数]
select * from test limit 1,4	//显示[1,4)行的数据

Code

package utils

import (
	"database/sql"

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

// 定义全局变量
var (
	Db  *sql.DB
	err error
)

func init() {
	Db, err = sql.Open("mysql", "root:123123@tcp(localhost:3306)/test")
	if err != nil {
		panic(err.Error())
	}
}
package model

import (
	"fmt"

	"gitee.com/mall_lucy/my_go_studycode/PrincipleLanguage/GORM/utils"
)

type User struct {
	ID       int
	Username string
	Password string
	Email    string
}

// AddUser 添加User方法
func (user *User) AddUser() error {
	// 写sql语句
	sqlStr := "insert into users(username,password,email) values(?,?,?)"

	/*
		// 执行(不执行预编译)
		_, err := utils.Db.Exec(sqlStr, "admin2", "888888", "admin@qq.com")
		if err != nil {
			fmt.Println("执行出现异常", err)
			return err
		}
	*/

	// 预编译
	inStmt, err := utils.Db.Prepare(sqlStr)
	if err != nil {
		fmt.Println("预编译异常", err)
		return err
	}

	// 执行
	_, err2 := inStmt.Exec("admin", "123456", "123@qq.com")
	if err != nil {
		fmt.Println("执行异常", err)
		return err2
	}

	return nil
}

// 根据用户的id从数据库中查询一条记录
func (user *User) GetUserByID() (*User, error) {
	// 写sql语句
	sqlStr := "select id,username,password,email from users where id = ?"
	// 执行一次查询返回一条结果
	row := utils.Db.QueryRow(sqlStr, user.ID)
	// 声明
	var id int
	var username string
	var password string
	var email string
	err := row.Scan(&id, &username, &password, &email)
	if err != nil {
		return nil, err
	}
	u := &User{
		ID:       id,
		Username: username,
		Password: password,
		Email:    email,
	}
	return u, nil
}

// 获取数据库中所有记录
func (user *User) GetUsers() ([]*User, error) {
	// 写Sql语句
	sqlStr := "select id,username,password,email from users"
	// 执行
	rows, err := utils.Db.Query(sqlStr)
	if err != nil {
		return nil, err
	}
	// 创建User切片
	var users []*User
	for rows.Next() {
		// 声明
		var id int
		var username string
		var password string
		var email string
		err := rows.Scan(&id, &username, &password, &email)
		if err != nil {
			return nil, err
		}
		u := &User{
			ID:       id,
			Username: username,
			Password: password,
			Email:    email,
		}
		users = append(users, u)
	}
	return users, nil
}

package model

import (
	"fmt"
	"testing"
)

func TestMain(m *testing.M) {
	fmt.Println("测试开始:")
	m.Run()
}

func TestUser(t *testing.T) {
	fmt.Println("开始测试User中的相关方法")
	//执行子测试函数
	t.Run("测试添加用户:", testGetUser)
}

// 如果函数名不是以Test开头,那么该函数默认不执行,我们可以将它设置成一个子测试函数
func TestAddUser(t *testing.T) {
	fmt.Println("测试添加用户:")
	user := &User{}
	// 调用添加用户方法
	user.AddUser()
}

// 测试获取一个User
func TestGetUserByID(t *testing.T) {
	fmt.Println("查询一条记录的子测试函数执行:")
	user := User{
		ID: 1,
	}
	// 调用获取User的方法
	u, _ := user.GetUserByID()
	fmt.Println("得到的User的信息是:", u)
}

// 测试获取所有user
func testGetUser(t *testing.T) {
	fmt.Println("测试所有记录:")
	user := User{}
	// 调用获取说有User的方法
	us, _ := user.GetUsers()
	// 遍历切片
	for k, v := range us {
		fmt.Printf("第%v用户是%v:\n", k+1, v)
	}
}