咖啡丶七

自律给我自由

合并分支

合并

使用git merge <branchName>命令将<branchName>分支上的内容合并到当前所在的分支上

<branchName> 可以是分支的名字,也可以是commitID

出现冲突

出现如下内容,说明自动合并发生了冲突,需要手动解决冲突

使用git status查看冲突文件

使用git diff查看冲突内容

解决冲突

解决冲突的三种方法

方法一:直接编辑

使用vim <fielName>编辑该文件,留下我们需要的内容
随便怎么改都行,你就把它想成是重新编辑文件,只不过给了你两个版本的提示

修改前:

修改后:

方法二:保留选择的版本

选择当前分支的版本作为解决方案

1
git checkout --ours <fileName>

选择合并分支的版本

1
git checkout --theirs <fileName>
方法三:强行退出merge模式

该命令将会放弃合并过程并且尝试重建合并前的状态

1
git merge --abort

保存提交

最后再重新提交一遍就成功的解决了冲突

销毁所有子物体后,获取子物体的数量为0

如果在同一帧内需要增加子物体并统计新的子物体的数量可以使用这个方法

1
2
3
4
5
6
for (int i = 0; i < coneten.childCount; i++)
{
DestroyImmediate(content.GetChild(0).gameObject);
Debug.Log(content.childCount); # 输出的值会慢慢的变小,直至变为0
}
Debug.Log(content.childCount); # 输出为0

注意:这里的for循环获取子物体的方法是GetChild(o)

销毁所有子物体后,获取子物体的数量为销毁前的数量

1
2
3
4
5
6
for (int i = 0; i < content.childCount; i++)
{
Destroy(content.GetChild(i).gameObject);
Debug.Log(content.childCount); # 输出的一直是销毁前的子物体数量
}
Debug.Log(content.childCount); # 输出的是销毁前的子物体数量

1
2
3
4
5
6
foreach (RectTransform item in content)
{
Destroy(item.gameObject);
Debug.Log(content.childCount); # 输出的一直是销毁前的子物体数量
}
Debug.Log(content.childCount); # 输出的是销毁前的子物体数量

注意:这里的for循环中获取子物体的方法是GetChild(i),这种for循环方式和forecho是一样的

销毁子物体错误的方法

这种方法销毁不干净子物体

1
2
3
4
5
foreach (RectTransform item in content)
{
DestoryImmediate(item.gameObject);
}
Debug.Log(content.childCount);

JSON文件

  • 序列:通俗来说就是字符串
  • 序列化:将代码中的对象(如:列表、字典等)转换成字符串,以便将信息保存在文件中或传输到网络上
  • 反序列化:将字符串转换成代码中的对象

序列化

序列化 (Serialization),是指把程序中的一个类转化成一个标准化的格式。标准化的意义是这个格式可以跨程序,跨平台的被使用,而且保持其原有的内容,规范。

json.dumps(<对象>)将对象转换成字符串,可添加参数indent=4设置字符串的缩进

1
2
3
dict_ = {"name": "John", "age": 30}
s = json.dumps(dict_)
print(s) # 输出:'{"name": "John", "age": 30}'

json.dump(<对象>, <file>)将对象写入到file文件中,可添加参数indent=4设置字符串的缩进

1
2
3
dict_ = {"name": "John", "age": 30}
with open('data.json', 'w') as json_file:
json.dump(dict_, json_file)

反序列化

json.loads(<string>)string转换成对象并返回

1
2
3
s = '{"name": "John", "age": 30}'
dict_ = json.loads(s)
print(dict_) # 输出:{"name": "John", "age": 30}

json.load(<file>)file文件中的内容转换成对象并返回

1
2
3
with open('data.json', 'r') as file:
dict_ = json.load(file)
print(dict_) # 输出:{"name": "John", "age": 30}

总结

json.dumps(<对象>):将对象转换成字符串,作用的转换

json.dump(<对象>, <file>):将对象写入file文件中,作用是转换并写入

json.loads(<string>):将string转换成对象并返回,参数是string

json.load(<file>):将file文件中的内容转换成对象并返回,参数是file

StreamingAssets方法

这是一个只读不可写的目录;该文件夹的资源会保持原始格式(比如图片不会被引擎进行纹理压缩),dll文件或脚本放在该文件夹下也不会参与编译

官方推荐使用Application.streamingAssetsPath来获取该文件夹的实际位置,其可规避平台差异:
对于UnityEditor,windows平台,其等价于:Application.dataPath + "/StreamingAssets"
对于macOS,其等价于:Application.dataPath+"/Resources/Data/StreamingAssets"
对于ios平台,其等价于:Application.dataPath + "/Raw";
对于android平台,其等价于:"jar:file://" + Application.dataPath + "!/assets/";

基础使用方法:

1
2
3
4
// 设置路径
string jsonPath = Application.streamingAssetsPath + @"/JSON/IP.json";
// 读取文件
string jsonStr = System.IO.File.ReadAllText(jsonPath, Encoding.UTF8);

对于非Android和WebGL平台,支持File或者Stream的读取操作
但是对于Android和WebGL平台上无法访问StreamingAssets文件夹。在WebGL上没有文件访问权。Android使用压缩的.apk文件。这些平台无法返回URL。
解决方案:

  1. 把StreamingAssets下的文件写入persistentDataPath,后续的读取和写入都在persistentDataPath进行
  2. 使用UnityWebRequest对StreamingAssets下的文件进行读取

使用UnityWebRequest读取

UnityWebRequest读取文件需要传入文件的URL,StreamingAssets目录不同平台对应的URL是不一样的,如下:

  • Window平台 file:///D:/DATA/StreamingAssets/data.json
  • WebGL平台 http://localhost/StreamingAssets/data.json
  • Android平台 jar:file:///data/app/xxx!/assets/data.json
  • IOS平台 Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw

这时候最好通过构造Uri()的方式来规避平台的差异,获得真正的请求URL。如:

1
var uri = new System.Uri(Path.Combine(Application.streamingAssetsPath, "data.json")).AbsoluteUri;

方法Path.Combine(Path1, Path2)在检测到path1不是以分隔符结尾的话,会自动补充分隔符


PersistentDataPath方法

该方法下的文件可读可写

使用这个方法生成的文件所在路径为:C:\Users\Administrator\AppData\LocalLow\DefaultCompany\项目名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.IO;

// 设置路径
string filePath = Path.Combine(Application.persistentDataPath, "config.json");
// 判断文件是否存在
if (!File.Exists(filePath))
{
try //如果文件不存在,创建一个新文件
{
// 创建文件并写入内容
File.WriteAllText(filePath, "{ \"settingCycle\", 999 }"));
Debug.Log("Remark file created successfully.");
}
catch (System.Exception ex) // 如果创建失败会捕获错误
{
Debug.LogError("Failed to create remark file: " + ex.Message);
}
}
// 有了前面的兜底创建文件的步骤,这一步就可以直接读取该路径下的文件了
string jsonContent = File.ReadAllText(filePath);

Resources方法

是存储资源的文件的方法,如音频、视频、预制体等
在读取文件时可以不加后缀
只可读
打包后文件夹内容会被加密,无法直接看到该文件夹下的内容

1
2
// 读取Resources文件夹下的内容
prefab = UnityEngine.Resources.Load<GameObject>("BayWindow/prefabObject");

通用方法

这种方法可以将文件存储在与Assets同级路径下
可以读取文本文件和资源文件

1
2
3
4
5
6
7
8
// 先制定好根路径
string DynamicParent = Application.dataPath + "/../资源/";
// 设置路径
string descriptionPath = "文本文件/start.text";
// 创建文件,后立刻释放相关资源
File.Create(DynamicParent + descriptionPath).Dispose();
// 读取文件
string content = File.ReadAllText(DynamicParent + descriptionPath)

拓展:在创建文件前可以先创建该文件的父级文件夹

1
2
3
4
5
6
7
8
// 获取文件的父级文件夹路径
parentPath = System.IO.Path.GetDirectoryName(DynamicParent + descriptionPath);
// 判断父级文件夹是否存在,如果不存在就创建
if (!Directory.Exists(parentPath))
Directory.CreateDirectory(parentPath)
// 判断该文件是否存在,如果不存在就创建
if (!File.Exists(DynamicParent + descriptionPath))
File.Create(DynamicParent + descriptionPath).Dispose();

Path.GetDirectoryName(path)是获取path这个路径的父文件路径,具体用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
string filePath = @"C:\MyDir\MySubDir\myfile.ext";
string directoryName;
int i = 0;

while (filePath != null)
{
directoryName = Path.GetDirectoryName(filePath);
Console.WriteLine("GetDirectoryName('{0}') returns '{1}'",
filePath, directoryName);
filePath = directoryName;
if (i == 1)
{
filePath = directoryName + @"\"; // this will preserve the previous path
}
i++;
}
/*
This code produces the following output:

GetDirectoryName('C:\MyDir\MySubDir\myfile.ext') returns 'C:\MyDir\MySubDir'
GetDirectoryName('C:\MyDir\MySubDir') returns 'C:\MyDir'
GetDirectoryName('C:\MyDir\') returns 'C:\MyDir'
GetDirectoryName('C:\MyDir') returns 'C:\'
GetDirectoryName('C:\') returns ''
*/

参考:

详解Unity中的StreamingAssets文件夹


2023-09-02 运动

昨晚加班加猛了,一直加到转钟,没有跑步


2023-09-10 运动

出差了一周,一周没跑了
今天暂时只跑个一圈半热身一下吧


2023-09-11 跑步


2023-09-14 跑步


2023-09-17 跑步

MySQL客户端

  • 如果安装了MySQL-Shell可以直接使用mysqlsh进入MySQL-Shell客户端,然后使用\connect root@localhost来连接数据库
  • 也可以使用mysql -u root -p来进入MySQL客户端

MySQL-Shell语法

语法 解释
\connect root@localhost 连接数据库
\help 帮助
\py 切换到python语言
\sql 切换成sql语言
\js 切换成js语言
\use <database_name> 切换并进入数据库

数据库语法

语法 解释
SHOW DATABASES; 展示所有数据库
CREATE DATABASE <database_name>; 创建数据库
DROP DATABASE <database_name>; 删除数据库
USE <database_name>; 选择数据库

数据导入和导出

导出

在MySQL-Shell中使用命令

1
2
3
4
# -u指定用户,-p后续输入密码,game > game.sql将数据库game导出到game.sql文件中
mysqldump -u root -p game > game.sql
# 将game数据库的player表导出到player.sql中
mysqldump -u root -p game player > player.sql

导入

在Shell中使用命令

1
2
# 将game.sql的数据导入到game数据库中
mysql -u root -p game < game.sql

表结构

语法 解释
DESC <table_name> 展示表结构
SHOW TABLES; 展示所有表
CREATE TABLE <table_name> <表的结构定义>; 创建表
DROP TABLE <table_name>; 删除表

定义表结构

在创建表的时候可以,定义列名、列的数据类型表结构

1
2
3
4
5
6
7
CREATE TABLE player (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -- 列名为id,数据类型为INT,不能为NULL,并且设置为自增长的主键
name VARCHAR(100) UNIQUE, -- 长度为100的变长字符串这个字段必须为唯一值
level INT DEFAULT 1, -- 列名为level,数据类型为INT,默认值为1
exp INT,
gold DECIMAL(10,2) -- 长度为10,并且保留两位小数的十进制数
);

修改表结构

1
2
3
4
-- 添加列
ALTER TABLE <table_name> ADD <col> <value_type>;
-- 删除列
ALTER TABLE <table_name> DROP <col>;
1
2
-- 将player表的level列的数据类型设置为INT,默认值设置为1
ALTER TABLE player MODIFY level INT DEFAULT 1;
语法 解释
ALTER TABLE <table_name> MODIFY <col> <value_type> DEFAULT <value>; 设置默认值为<value>
ALTER TABLE <table_name> MODIFY <col> <value_type> [NOT] NULL; 设置[不]可以为NULL
ALTER TABLE <table_name> ADD UNIQUE (<col>); 设置为唯一性,需要使用括号
ALTER TABLE <table_name> MODIFT <col> <value_type> PRIMARY KEY; 设置为主键,唯一且不为空
ALTER TABLE <child_table> ADD FOREIGN KEY (<child_col>) REFERENCES <parent_table> (parent_col); 设置从键
ALTER TABLE <table_name> ADD INDEX <index_name> (col); 设置索引

<child_table>是从表

<child_col>是从表中的外键列

<parent_table>是主表

<parent_col>是主表中的主键列


数据的增删改

1
2
-- 在<table_name>表中插入<col1>为<value1>,<col2>为<value2>,<col3>为<value3>的数据
INSERT INTO <table_name> (<col1>, <col2>, <col3>) VALUES (<value1>, <value2>, <value3>);

VALUES后面的数据与列的个数对应,则可以不用写列

e.g. INSERT INTO player (id, name, level) VALUES (1, '张三', 10);可以写成 INSERT INTO player VALUES (1, '张三', 10);

也可以只使用部分列,没有使用的列将使用默认值

e.g. INSERT INTO player (id, name) VALUES (2, '李四');没有被定义的level将以默认值代替

也可以同时插入多条数据

e.g. INSERT INTO player (id, name) VALUES (3, '王五'), (4, '赵六');

1
2
-- 删除<table_name>表中所有<col>列为<value>的数据
DELETE FROM <table_name> WHERE <col>=<value>;

e.g. DELETE FROM test;删除test表中所有的数据

1
2
-- 将<tablue_name>表的<col2>列为<value2>数据的<col1>赋值为<value1>
UPDATE <table_name> SET <col1> = <value1> WHERE <col2> = <value2>;

e.g. UPDATE player SET level = 1 WHERE name = '李四';将李四的等级修改为1

不加WHERE限制范围就是对所有的数据修改,多个设置可以使用,隔开

e.g. UPDATE player SET level=1, exp=0;将所有玩家的等级修改为1,经验修改为0


查询语句

语法 解释
SELECT <col> FROM <table>; 显示<table>表中的<col>列中的数据
SELECT <col> FROM <table> WHERE <condition>; 显示<col>中符合<condition>的数据
SELECT <col> FROM <table> ORDER BY <col> ASC|DESC; 按照排序显示查询数据

WHERE <condition>限制查询目标语法

  • 可以使用<,>,=
  • 多个条件可以使用ANDOR连接(需要注意优先级AND优先于OR,还可以使用括号改变优先顺序)
  • 使用IN限制范围,e.g. WHERE level IN (1, 3, 5)限制条件为:等级等于1,3,5
  • 使用WHERE <col> BETWEEN <num1> AND <num2>限制范围,e.g. WHERE level BETWEEN 1 AND 10:等级在1到10之间(包括1和10),等价于WHERE level >= 1 AND level <= 10
  • 使用NOT取反
  • 使用LINK关键字(简化版的正则表达式):WHERE name LINK '王%',查找所有姓王的玩家,%可以代替多个字符,_代替一个字符
  • 使用REGEXP关键字(正则表达式)

注意事项

数据库中null “空”不等于"" “空字符串”

  • 查找null ‘’空’’:WHERE email is null
  • 查找"" “空字符串”:WHERE email = ''

ORDER BY <col> ASC|DESC排序语法

  • ASC升序,默认就是升序,可省略不写
  • DESC降序

e.g. ORDER BY level DES, exp ASC等级降序,经验升序

聚合函数

聚合函数对某列执行一些计算,比如返回项目COUNT(),求和SUN()、平均AVG()、最大值MAX()、最小值MIN()

1
2
3
4
-- 返回所有玩家的总人数
SELECT COUNT(*) FROM player
-- 返回所有玩家的平均等级
SELECT AVG(level) FROM player

GROUP BY分组语法

1
2
-- 将所有玩家以sex这一列分组,并展示其和
SELECT sex, COUNT(*) FROM player GROUP BY sex;

输出结果:男有140,女有65,NULL有3,””有1

1
2
3
4
5
6
7
8
9
10
 MySQL  localhost:33060+ ssl  game  SQL > SELECT sex, count(*) FROM player GROUP BY sex;
+------+----------+
| sex | count(*) |
+------+----------+
| 男 | 140 |
| 女 | 65 |
| NULL | 3 |
| | 1 |
+------+----------+
4 rows in set (0.0008 sec)

GOUP BY经常与HAVINGORDER BY搭配使用

1
2
3
4
-- 将等级分组统计数量,再显示大于4个的组
SELECT level, COUNT(*) FROM player GROUP BY level HAVING COUNT(*) > 4;
-- 将等级分组统计数量,再显示大于4个的组,并按降序排列
SELECT level, COUNT(*) FROM player GROUP BY level HAVING COUNT(*) > 4 ORDER BY count(level) DESC;

LIMIT [num1] num2语法

用来控制显示数量和范围

  • num1可选参数,偏移量。如果为4,表示从第5个数开始展示
  • num2显示的数量
1
2
3
4
5
6
7
8
9
-- 显示前三条数据
SELECT id, name FROM player LIMIT 3;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
| 2 | 赵四儿 |
| 3 | 王五 |
+----+--------+
1
2
3
4
5
6
7
8
9
-- 从第5条数据开始,显示三条
SELECT id, name FROM player LIMIT 4, 3;
+----+--------+
| id | name |
+----+--------+
| 5 | 范德彪 |
| 6 | 马大帅 |
| 7 | 王小二 |
+----+--------+

DISTINCT <col>去重

1
2
-- 显示去重后的性别
SELECT DISTINCT sex FROM player;

UNION [ALL]并集

集合A有α,集合B也有α,查询结果α默认只会显示一次

加上ALL之后,α会显示两次

1
2
3
4
5
6
7
8
-- 查询等级在1到3  或  经验在100到500之间的玩家,重复的只会显示一次
SELECT * FROM player WHERE level BETWEEN 1 AND 3
UNION
SELECT * FROM player WHERE exp BETWEEN 100 AND 500;
-- 查询等级在1到3 或 经验在100到500之间的玩家,重复的会多次选择
SELECT * FROM player WHERE level BETWEEN 1 AND 3
UNION ALL
SELECT * FROM player WHERE exp BETWEEN 100 AND 500;

INTERSECT交集

1
2
3
4
-- 查询等级在1到3  且  经验在100到500之间的玩家
SELECT * FROM player WHERE level BETWEEN 1 AND 3
INTERSECT
SELECT * FROM player WHERE exp BETWEEN 100 AND 500;

EXCEPT差集

1
2
3
4
-- 查询等级在1到3  且  经验 不 在100到500之间的玩家
SELECT * FROM player WHERE level BETWEEN 1 AND 3
EXCEPT
SELECT * FROM player WHERE exp BETWEEN 100 AND 500;

综合练习

1
2
3
4
5
SELECT SUBSTR(name, 1, 1), COUNT(SUBSTR(name, 1, 1)) FROM player		-- 选择表和要显示的列
GROUP BY SUBSTR(name, 1, 1) -- 截取name:从第一个字符串开始,截取一个长度
HAVING COUNT(SUBSTR(name, 1, 1)) >= 5 -- 展示数量大于5的
ORDER BY COUNT(SUBSTR(name, 1, 1)) DESC -- 降序
LIMIT 3, 4 -- 限制显示的数量,和偏移量:只显示3个,并向后偏移4位,显示5,6,7

子查询

可以将查询结果看成一个整体,使用在大多数语法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 查询大于平均等级的玩家
SELECT * FROM player where level > (SELECT AVG(level) FROM player);
-- 查询等级与平均等级的差值
SELECT level,
(SELECT AVG(level) FROM player) as average, -- 使用as关键字将这一列的名称变为average,原名称为(SELECT AVG(level) FROM player)
level - (SELECT AVG(level) FROM player) as diff
FROM player;
-- 将查询结果创建成一个新的表
CREATE TABLE player1 (SELECT id, name, level FROM player WHERE level BETWEEN 1 AND 5);
-- 将查询的结果添加到其他表中
INSERT INTO player1 (SELECT id, name, level FROM player WHERE level BETWEEN 5 AND 10); -- 这样新建的表player1中就有等级1到10的玩家了
-- 判断是否存在值,只会返回0和1
SELECT EXISTS (SELECT * FROM player1 WHERE level > 10); -- 返回0,没有结果
SELECT EXISTS (SELECT * FROM player1 WHERE level > 5); -- 返回1,有结果

表关联

用来查询多个表中的数据,关联的表中必须有相同的字段

一般会使用表的主键和外键来关联

INNER JOIN内连接

只返回两个表都有的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 查询并显示玩家表的id和武器表的player_id相同的数据(玩家排在前面)
SELECT * FROM player INNER JOIN equip ON player.id = equip.player_id;
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| 玩家表 | 武器表 |
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| id | name | sex | email | level | exp | gold | id | name | player_id |
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| 76 | 林克 | 男 | linke@qq.com | 48 | 12 | 11.00 | 6 | 大师之剑 | 76 |
| 157 | 张飞 | 男 | zhangfei@gmail.com | 76 | 36 | 80.00 | 2 | 丈八蛇矛 | 157 |
| 161 | 孙悟空 | 男 | sunwukong@gmail.com | 74 | 32 | 23.00 | 7 | 金箍棒 | 161 |
| 177 | 关羽 | 男 | guanyu@gmail.com | 19 | 60 | 36.00 | 1 | 青龙偃月刀 | 177 |
| 186 | 曹操 | 男 | caocao@geekhour.net | 70 | 15 | 27.00 | 3 | 七星宝刀 | 186 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 9 | 赤兔马 | 190 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 8 | 方天画戟 | 190 |
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 查询并显示武器表的player_id和玩家表的id相同的数据(武器表排在前面)
SELECT * FROM equip INNER JOIN player ON equip.player_id = player.id;
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| 武器表 | 玩家表 |
+----+------------+-----------+-----+--------+-----+---------------------+-------+-----+-------+
| id | name | player_id | id | name | sex | email | level | exp | gold |
+----+------------+-----------+-----+--------+-----+---------------------+-------+-----+-------+
| 6 | 大师之剑 | 76 | 76 | 林克 | 男 | linke@qq.com | 48 | 12 | 11.00 |
| 2 | 丈八蛇矛 | 157 | 157 | 张飞 | 男 | zhangfei@gmail.com | 76 | 36 | 80.00 |
| 7 | 金箍棒 | 161 | 161 | 孙悟空 | 男 | sunwukong@gmail.com | 74 | 32 | 23.00 |
| 1 | 青龙偃月刀 | 177 | 177 | 关羽 | 男 | guanyu@gmail.com | 19 | 60 | 36.00 |
| 3 | 七星宝刀 | 186 | 186 | 曹操 | 男 | caocao@geekhour.net | 70 | 15 | 27.00 |
| 9 | 赤兔马 | 190 | 190 | 吕布 | 男 | | 77 | 43 | 31.00 |
| 8 | 方天画戟 | 190 | 190 | 吕布 | 男 | | 77 | 43 | 31.00 |
+----+------------+-----------+-----+--------+-----+---------------------+-------+-----+-------+

LEFT INJO左连接

返回左表中所有的数据,和右表中匹配的数据(右表中没有的数据用NULL填充)

1
2
-- 显示player表,并将equip表依据player.id = equip.player_id挂载在后面
SELECT * FROM player LEFT JOIN equip ON player.id = equip.player_id;

数据较多就不显示例子了,与内连接第一个例子结果类似

RIGHT INJO右连接

返回右表中所有的数据,和左表中匹配的数据(左表中没有的数据用NULL填充)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 显示equip表,并将player表依据player.id = equip.player_id挂载在后面
SELECT * FROM player RIGHT join equip on player.id = equip.player_id;
+------+--------+------+---------------------+-------+------+-------+----+------------+-----------+
| id | name | sex | email | level | exp | gold | id | name | player_id |
+------+--------+------+---------------------+-------+------+-------+----+------------+-----------+
| 177 | 关羽 | 男 | guanyu@gmail.com | 19 | 60 | 36.00 | 1 | 青龙偃月刀 | 177 |
| 157 | 张飞 | 男 | zhangfei@gmail.com | 76 | 36 | 80.00 | 2 | 丈八蛇矛 | 157 |
| 186 | 曹操 | 男 | caocao@geekhour.net | 70 | 15 | 27.00 | 3 | 七星宝刀 | 186 |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | 4 | 长剑 | NULL |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | 5 | 铁盾 | NULL |
| 76 | 林克 | 男 | linke@qq.com | 48 | 12 | 11.00 | 6 | 大师之剑 | 76 |
| 161 | 孙悟空 | 男 | sunwukong@gmail.com | 74 | 32 | 23.00 | 7 | 金箍棒 | 161 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 8 | 方天画戟 | 190 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 9 | 赤兔马 | 190 |
+------+--------+------+---------------------+-------+------+-------+----+------------+-----------+

WHERE关联

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 在player表和equip表中查询并显示player.id = equip.player_id相等的数据
SELECT * FROM player, equip WHERE player.id = equip.player_id;
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| id | name | sex | email | level | exp | gold | id | name | player_id |
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
| 76 | 林克 | 男 | linke@qq.com | 48 | 12 | 11.00 | 6 | 大师之剑 | 76 |
| 157 | 张飞 | 男 | zhangfei@gmail.com | 76 | 36 | 80.00 | 2 | 丈八蛇矛 | 157 |
| 161 | 孙悟空 | 男 | sunwukong@gmail.com | 74 | 32 | 23.00 | 7 | 金箍棒 | 161 |
| 177 | 关羽 | 男 | guanyu@gmail.com | 19 | 60 | 36.00 | 1 | 青龙偃月刀 | 177 |
| 186 | 曹操 | 男 | caocao@geekhour.net | 70 | 15 | 27.00 | 3 | 七星宝刀 | 186 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 9 | 赤兔马 | 190 |
| 190 | 吕布 | 男 | | 77 | 43 | 31.00 | 8 | 方天画戟 | 190 |
+-----+--------+-----+---------------------+-------+-----+-------+----+------------+-----------+
1
2
-- 可以给表名赋上别名,和上面的结果是一样的
SELECT * FROM player p, equip e WHERE p.id = e.player_id;

索引

是一种用来提高查询效率的数据结构,可以帮助我们快速的定位到我们想要的数据

如果没有索引的话,就只能从头开始遍历所有的数据,直到找到满足条件的数据为止。当数据非常少的时候没有什么问题,但是当数据量非常大的时候,查询效率就会直线下降,索引就是为了解决这个问题而产生的

创建索引

1
CREATE [UNIQE|FULLTEXT|SPATYAL] INDEX <index_name> ON <table_name(index_col_name,...)>

[UNIQE|FULLTEXT|SPATYAL]:分别代表唯一索引、全文索引、空间索引。可不写,默认为唯一索引

<index_name>:索引名称

<table_name(index_col_name,...)>:给指定的表的指定列创建索引

e.g.:CREATE INDEX email_index ON player(name)

在创建表的同时添加索引:

1
2
3
4
5
6
CREATE TABLE player (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL,
INDEX name_index (name) -- 给name列创建索引
);

查看索引

1
2
3
4
5
6
7
8
SHOW INDEX FROM <talbe_name>
# 输出:
+--------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| player | 1 | name_index | 1 | name | A | 209 | NULL | NULL | YES | BTREE | | | YES | NULL |
+--------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

索引的使用

上面使用CREATE INDEX email_index ON player(name);给player的name添加了索引

使用方法:直接查找这个表的这个列SELECT * FROM player WHERE name like "王%";就能很快速的查找出姓王的人了

删除索引

DROP INDEX <index_name> ON <table_name>;

e.g.: DROP INDEX name_index ON player;

还能使用修改表结构的方式添加索引:ALTER TALBE player ADD INDEX name_index (name);


数据类型

数值类型

数据类型 大小 范围(有符号) 范围(无符号) 用途
TINYINT 1 Bytes (-128,127) (0,255) 小整数值
SMALLINT 2 Bytes (-32,768,32,767) (0,65 535) 大整数值
MEDIUMINT 3 Bytes (-8,388,608,8 388,607) (0,16 777 215) 大整数值
INT或INTEGER 4 Bytes (-2,147,483,648,2,147,483,647) (0,4 294 967 295) 大整数值
BIGINT 8 Bytes (-9,223,372,036,854,775,808,9,223,372,036,854,775,807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 4 Bytes (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 Bytes (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 依赖于M和D的值 依赖于M和D的值 小数值

今天从零开始组装了一台电脑,用了7年的电脑终于退休了,说实话多多少少有点舍不得

下载

下载包体

编译环境

1
2
3
4
5
6
7
8
sudo yum install libcurl-devel
sudo yum install expat-devel
sudo yum install asciidoc
sudo yum install xmlto
sudo yum install docbook2X
# 设置软连接
ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2x-texi
ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2texi

根据git官网的指示,安装相关依赖包:yum install dh-autoreconf curl-devel expat-devel gettext-devel openssl-devel perl-devel zlib-devel libxslt asciidoc xmlto docbook2X autoconf install-info getopt

安装

解压tar -zxvf git-2.42.0.tar.gz

编译make prefix=/usr/local all doc info

安装make prefix=/usr/local install install-doc install-html install-info

可能会出现的问题

提示找不到docbook2x-texi或者docbook2texi

在执行yum install docbook2X后设置软连接

1
2
ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2x-texi
ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2texi

参考

使用源码方法在阿里云服务器CentOS 7安装Git

安装

下载包体

https://github.com/neovim/neovim/releases

安装

1
2
3
4
5
tar -zxvf neovim-0.8.0.tar.gz
# 解压后就可以直接用了,十分方便
./nvim-linux64/bin/nvim
# 可以将其放在/usr/local下,然后创建软链接
sudo ln -s /usr/local/nvim/bin/nvim /usr/bin/nvim

配置

创建配置文件

默认配置文件路径:
1
2
3
4
# 创建配置文件夹
mkdir ~/.config/nvim
# 创建配置文件
nvim ~/.config/nvim/init.vim
自定义配置文件的路径:
  1. 创建配置文件
1
2
3
4
5
cd /usr/local/nvim-linux64
mkdir ./config
mkdir ./config/nvim
# 创建配置文件
nvim ./config/nvim/init.vim

  1. nvim /etc/profile修改环境变量
1
2
3
# nvim配置文件
export XDG_CONFIG_HOME=/usr/local/nvim-linux64/config
export XDG_DATA_HOME=/usr/local/nvim-linux64/config

  1. 重载配置文件
1
source /etc/profile

基础配置

1
2
3
4
5
6
7
" 基础键位映射
imap jk <Esc>
nmap <space> :

" 显示相对行
set relativenumber
set number

安装vim-plug插件管理

前面不是命名了全局变量XDG_DATA_HOME吗,这个时候就用上了

plug.vim文件放在以下路径

windows: ./nvim-win64/config/nvim-data/site/autoload/

linux: ./nvim-linux64/config/nvim/site/autoload/

安装方法

  • 在nvim窗口下输入:PlugInstall
  • 在linux终端输入nvim +PlugInstall +qall

第一种安装方法可能会因为网络的原因安装失败,这时就可以使用第二种方法

如果出现Finishing … Done! 和 Already installed 就说明安装成功了

后面安装的插件位置会放在~/vim/plugged文件夹中

插件网站


我的配置

热键

imap 将输入模式的key1映射到key2(key1和key2都有key2的功能)
nmap 将命令模式的key1映射到key2上

特殊键位

alt + q
Ctrl + q
esc键
空格

其他设置

set number 显示行号(或者set nu)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
" 基础键位映射
imap jk <Esc>
nmap <space> :

" 显示相对行
set relativenumber
set number

" /的搜索忽略大小写
set ignorecase


call plug#begin()

Plug 'scrooloose/nerdtree'
Plug 'rkulla/pydiction'

call plug#end()




" nerdtree插件绑定
" 使用ctrl+e打开关闭
map <silent> <C-e> :NERDTreeToggle<CR>

" 将光标移动到NERDTree中
nnoremap <C-w> <C-w>w

" vim启动时自动显示NERDTree
"auto VimEnter * NERDTree

" 打开vim时如果没有文件自动打开NERDTree
autocmd vimenter * if !argc()|NERDTree|endif

" 当NERTreed为剩下的唯一窗口时自动关闭
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif

" 设定NERTree视窗大小
"let g:NERDTreeWinSize=30

" 修改树的显示图标
let g:NERDTreeDirArrowExpandable = '+'
let g:NERDTreeDirArrowCollapsible = '-'

" 隐藏文件
let NERDTreeIgnore = ['\.pyc$', '__pycache__']

" 是否显示行号
"let g:NERDTreeShowLineNumbers=1

" 是否显示隐藏文件 NERDTree自带的快捷键Ctrl+I,大写I
let g:NERDTreeHidden=0



" pydiction插件 python补全
filetype plugin on
let g:pydiction_location = '$XDG_CONFIG_HOME\\nvim-data\\plugged\\pydiction\\complete-dict'



用户

切换用户

1
sudo -u {username} -s

创建用户

1
sudo useradd -m -s /bin/bash {username}
  • -m:创建用户的同时,创建用户的/home/{usrname}目录
  • -s /bin/bash:指定用户的默认登入shell为Bash

如果不用-s /bin/bash会出现无法使用上下左右方向键的问题
使用cat /etc/passwd可以看到{username}的登入shell是/bin/sh
使用ls -l /bin/sh,发现/bin/sh -> dash
修改连接目录sudo ln -sf /bin/bash /bin/sh,重新登入账户就可以了

1
sudo passwd {username}

为新用户设置密码,需要输入两次

删除用户

1
sudo userdel -r {username}

删除用户及其相关的文件,包括/home/{username}文件

给新用户root权限

通过将新用户添加到sudo组来给予root权限

1
sudo usermod -aG sudo {username}

验证:执行sudo ls /root,需要输入用户密码确认权限

查看用户和组

命令 解释
cat /etc/passwd 列出所有用户信息,每一行对应一个用户
who或者w 查看当前登入的用户
id {username} 查看指定用户

/etc/passwd文件内容:

1
2
root:x:0:0:root:/root:/bin/bash
steam:x:1000:1000::/home/steam:/bin/sh

使用:分割

  • steam:用户名
  • x:加密的密码字段(为了安全不再存在该文件下,而是存在/etc/shadow下)
  • 1000:用户ID(UID)
  • 1000:组ID(GID)
  • **:用户描述信息,一般为空
  • /home/steam:用户的主目录
  • /bin/sh:用户登入的shell
命令 解释
cat /etc/group 查看所有组,每一行对应一个组
groups {username} 查看{username}所在组

防火墙

基础命令

基础命令 效果
systemctl start firewalld.service 开启防火墙
systemctl status firewalld.service 查看防火墙状态
systemctl stop firewalld.service 关闭防火墙
systemctl enable firewalld.service 开启时自启
systemctl disable firewall.service 关闭开机自启
systemctl is-enable firewall.service 查看服务是否开机自启
systemctl --failed 查看启动失败的服务列表

配置防火墙

命令 效果
firewall-cmd --zone=public --list-ports 查看开放的端口
firewall-cmd --reload 重新载入防火墙
firewall-cmd --zone=public --add-port=80/tcp --permanent 开放80端口,--premanent表示永久开放,重启后也依然开放

每次在配置完防火墙之后需使用firewall-cmd --reload更新配置


文件操作

cat 查看文件
touch 创建文件
mkdir 创建文件夹
cp fileName 复制文件(后面的地址,不用加文件名)
mv 移动文件
mv 修改文件名称
rm 删除文件
rm -r 删除空文件夹 -f 强制删除,不用确认
cd
pwd 显示当前所在路径
cd - 返回上一次所在路径

文件权限

r:4 w:2 x:1

owner = rwx = 4+2+1 =7

chmod [-R] xyz

将owner/group/others及其子文件都设置为可读可写可执行

chmod -R 777 fileName


端口

netstat -lntp 查看网络连接状态和端口情况
lsof -i :5000 查看5000端口的进程PID,然后可以使用sudo kill 关闭这个进程

进程

top 查看系统实时状态,可以使用top -b -d 10 -n 10 > top_log.txt 来将内容保存下来(每十秒保存一次,共保存10次)
ps -ef 查看所有进程可以通过 ps -ef | grep 来筛选

解压/压缩

.tar tar xvf FileName.tar 解压
tar cvf FileName.tar DirName 压缩 tar cvf {newname.tar} {path/to/name}
.tar.xz tar xvf FileName.tar.xz
tar cvf FileName.tar DirName
.tar.gz tar zxvf FileName.tar.gz
tar zcvf FileName.tar.gz DirName
zip unzip FileName.zip
zip FileName.zip DirName