重学Mysql

Mysql函数(5.7)查询手册
Mysql函数(8.0)查询手册
Mysql基础教程

连接数据库

1
2
3
4
5
6
7
## 连接本地数据库
mysql -u用户名 -p密码
mysql -uroot -proot

## 连接远程数据库
mysql -u用户名 -p密码 -h远程数据库IP地址 -P端口 -D数据库名
mysql -uroot -proot -h192.168.1.88 -p3306 -Dtest

sql基本语句

1
2
3
4
5
6
## 查看数据库版本
select version();
## 查看数据库当前时间
select now();
## 查看用户
select user();
1
2
3
4
5
6
7
8
9
10
## 创建库(注意:库名多是大写字母)
create database 库名;
## 查看有哪些库
show databases;
## 删除某个库
drop database 库名;
## 创建库时制定编码格式
create database 库名 character set utf8;
## 进入某一个库下
use 库名;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 创建一个数据库表
create table person{
name varchar(10),
sex varchar(2),
age int
};
## 查看该仓库下的所有表
show tables;
## 查看某个表的所有列及列的数据类型
desc 表名;
## 查看创建表的详细语句,数据库引擎及字符编码
show create table
## 表重命名
alter table 旧名 rename 新名
## 删除表
drop table 表名;

增删改查

1
2
3
4
5
6
## 插入所有列
insert into person values("zhangsan","男",18);
## 插入部分列
insert into person(name,age) values("zhangsan",18);
## 插入查询出来的数据
insert into user(username) select name from account;

1
2
3
4
5
6
7
8
9
10
## 查看所有数据
select * from person;
## 查看符合条件的数据
select * from person where age = 18;
## 查看通过符合多个条件的数据
select * from person where age = 18 and sex = '男';
## 查看部分列数据
select name,sex from person where age = 18;
## 别名的使用,注:as可以省略
select name as "姓名" ,sex as "性别" from person where age = 18;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## 更新所有数据
update person set name = 'lisi';
## 更新符合条件的数据
update person set name = 'lisi' where age = 18;
## 修改字段数据类型
alter table 表名 modify 字段名 字段类型
## 修改字段名
alter table 表名 change 旧字段名 新字段名 新字段类型
## 添加字段
alter table 表名 add 字段名 字段类型
## 删除字段
alter table 表名 drop 字段名 字段类型
## 删除表的外键约束
alter table 表名 drop foreign key 外键约束名
## 删除没有关联的表
drop table if exists 表名 (多个逗号隔开)

1
2
3
4
## 删除表中的所有数据(如果不加where表示删除所有数据)
delete from person where .....
## 删除表中所有数据
truncate table 表名;
  1. delete是逐行一条一条删除记录的,truncate则是直接删除原来的表,再重新创建一个一模一样的新表,而不是逐行删除表中的数据,执行数据比delete快
  2. delete删除后,配合事件回滚可以找回数据;truncate不支持事务的回滚,数据删除后无法找回
  3. delete删除数据后,系统不会重新设计自增字段的计数器;truncate晴空表记录后,系统会重新设置自增字段的计算器
  4. delete的使用范围更广,因为它可以通过where子句指定条件来删除部分数据;而truncate不支持where子句,只能删除整体。
  5. delete回返回删除数据的行数,而truncate只会返回0,没有任何意义

约束

主键约束及自增长

1
2
3
4
5
6
7
## 一个表中只能设置一个主键
create table person(
id int(11) primary key auto_increment,
name varchar(10),
sex varchar(2),
age int
);

字段唯一

1
2
3
4
create table user(
ID int primary key auto_increment,
PHONE_NUM varchar(11) unique
);

字段不能为空

1
2
3
4
5
create table user(
ID int primary key auto_increment,
USERNAME varchar(100) not null unique,
GENDER char(1) not null,
);

字段默认值

1
2
3
4
5
6
create table person(
id int(11) primary key auto_increment,
name varchar(10) default '',
sex varchar(2) default '男',
age int default 0
);

表达式

like

1
2
3
4
5
select * from person where name like '张三%'; 
select * from person where name like '%张三';
select * from person where name like '%张三%';
select * from person where name like '%张%三'%;
select * from person where name like '张三_';

排序

1
2
3
4
## 默认为升序(asc),降序使用desc
select * from person order by age (asc | desc)
## 排序可以同时指定两个关键词
select * from person order by age desc,name asc

分页

1
2
3
4
## 1的意思是从1开始,但是不包括12的意思是取2
select * from person limit 1,2
## 分页与排序同时使用时,必须先排序,后分页
select * from person order by age limit 1,2

聚合函数

1
2
3
4
5
6
7
8
## 统计数量是最好用count(1)
select sum(age) from person;
select sum(age) from person where id > 2;
select count(*) from person;
select count(1) from person;
select count('a') from person;
select count(age) from person;
select count(*) from person where id > 2;
1
2
3
select max(age) from person;
select min(age) from person;
select avg(age) from person;

分组

1
2
3
select age from person group by age;
select name,age from person group by name,age;
select age,count(1) from person group by age;

分组统计

1
select count(1) from (select age from person group by age) temp

分组获取最大值

1
2
## 统计各年龄的最大id
select max(id) ,age from person group by age;

having的使用

1
2
3
4
## where不能和group by一起使用,所以此时出现了having
select age from person group by age having age > 2;
select count(1),age from person group by age having count(1) > 1;
select age from person group by age having count(1) > 1;

having后面并不是所有字段都可以作为判断条件,必须是可以放在select 和 from之间的字段才能作为判断条件。

多表查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## student表
create table student(
id int(11) primary key auto_increment;
name varchar(100) default '',
age int(11) default 0
);

## score表
create table score(
id int(11) primary key auto_increment,
student_id int(11),
type varchar(100) default '',
score int(11) default 0
);

交叉查询

1
2
3
4
5
## 笛卡尔积运算
select * from student cross join score
select * from student st cross join score sc where st.id = sc.student_id;
## 开发中最常用的语句
select st.name st,age,sc.type,sc.score from student st,score sc where st.id = sc.student_id;

内连接查询

1
2
## 这种方式和交叉连接得到的结果相同,所以这种方式很少使用
select * from student st inner join score sc on st.id = sc.student_id;

外连接查询

1
2
3
4
## 左外连接(会获取到左边的所有数据)
select * from student st left outer join score sc on st.id = sc.student_id;
## 右外连接
select * from student st right outer join score sc on st.id = sc.student_id;

嵌套查询

1
select * from score where student_id in (select id from student where naem = 'zhangsan');

组合查询

1
2
3
4
5
6
7
8
## union中,所有查询的列数和列顺序必须相同
select cust_name, cust_contact, cust_email
from customers
where cust_state in ('a,'b','c')
union
select cust_name, cust_contact, cust_email
from customers
where cust_name = 'test';

索引操作

1
2
3
4
5
6
## 创建索引
create index user_index on user(id);
## 创建唯一索引
create unique index user_index on user(id);
## 删除索引
alter table user drop index user_index;

创建索引能提高查找效率,但是索引也有弊端。创建索引系统会自动维护一个索引表,每当数据增加,更新,删除时都需要更改索引表,所以创建索引会降低增加,更新,删除的效率。

创建索引的建议:

  1. 定义主键的数据列一定要建立索引
  2. 定义有外键的数据列一定要建立索引
  3. 对于经常查询的数据列最好建立索引
  4. 对于需要在指定范围内的快速或频繁查询的数据列最好创建索引
  5. 经常用在where句中的数据列最好创建索引
  6. 经常出现在关键字order by,group by,distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。

不建议创建索引:

  1. 对于那些查询中很少设计的列,重复值比较多的列不要建立索引
  2. 对于定义为text,image和bit的数据类型的列不要建立索引
  3. 对于经常存取的列避免建立索引
  4. 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个,。索引虽说提高了访问速度,但是太多索引会比较影响数据的更新操作
  5. 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字母排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被受用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。

sql数据类型

详细数据类型

数据类型 占用字节数 对比
整数
tinyint 1个字节(-128-127)
smallint 2个字节(-2的16次方~2的16次方-1)
mediumint 3个字节(-2的24次方~2的24次方-1)
int 4个字节(-2的32次方~2的32次方-1) 与java的int取值范围相同
bigint 8个字节(-2的64次方~2的64次方-1) 与java的long取值范围相同
小数
float(n,d)(n表示总位数,d表示小数位数) 单精度浮点型 4个字节 对应java的float
double(n,d)(n表示总位数,d表示小数位数) 双精度浮点型 8个字节 对应java的double
字符串
char(n) 固定长度,最多255个字符
varchar(n) 可变长度,最多65535个字符
tinytext 可变长度,最多255个字符
text 可变长度,最多65535个字符
mediumtext 可变长度,最多2的24次方-1个字符
longtext 可变长度,最多2的32次方-1个字符
时间
date 日期,只包含年月日
time 时间,只包含时分秒
datetime 日期和时间都包含
timestamp 时间戳
enum todo 待完善
set todo 待完善
  • int(3) 3只用于显示宽度,并不能限制取值范围和字节占用空间,文本的则限制字符串的长度
  • 常用的是datetime和timestamp,datetime存入的是时间,没有时区的概念。timestamp是时间戳,同时间戳在不同时区对应不同时间。
  • datetime是任意时间范围,timestamp是1970年到2038年
  • 一般在操作当前时间时使用timestamp,操作历史或者很远的未来时间时使用datetime
  • Char的存储速度比Varchar快,但是浪费存储空间

数据库关系设计

关系类型

  • 一对一关系
  • 一对多关系
  • 多对多关系

主键和外键

  • 一对一关系中,通常在主要表中设置主键,然后在次要表中设置外键
  • 一对多关系中,通常在“一”表中设置主键,在“多”表中设置外键
  • 多对多关系中,通常需要引用第三张表,称为关系表。在两个实体表中都设置主键,然后在关系表中设置外键。

  • 一个表中,要么有主键盘,要么有外键,否则这个表就是一个孤立的表
  • 在设有外键的表中一般也设置自己的主键,作用是便于扩展

三大范式

  • 第一范式,又称为原子性,即表中的所有字段都不能再拆分
  • 第二范式,满足第一范式,且不存在部分依赖,及非主属性必须完全依赖主属性。(主属性及主键,完全依赖是针对联合主键的情况,非主键列不能只依赖于主键的一部分)
  • 第三范式,满足第二范式,且不存在传递依赖,及非主属性不能于非主属性之间有依赖关系,非主属性必须直接以来主属性,不能间接依赖主属性。(A->B,B->C A->C)

事务处理

1
2
3
4
5
6
7
8
9
10
11
12
## 开始事务
start transaction;
## 插入操作 A
insert into 'user' values(xxx,xxx);
## 创建保留点
savepoint updateA;
## 插入操作 B
insert into 'user' values(yyy,yyy);
## 回滚到保留点updateA
rollback to updateA;
## 提交事务,只有操作 A 生效
commit;

权限控制

  • GRANT 和 REVOKE 可在几个层次上控制访问权限:
    • 整个服务器,使用GRANT ALL 和 REVOKE ALL
    • 整个数据库,使用 ON database.*;
    • 特定的表,使用ON database.table;
    • 特定的列
    • 特定的存储过程
  • 新创建的账户没有任何权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 创建账户
create user myuser identified by 'mypassword';
## 修改账户
update user set user = 'newuser' where user='myuser';
flush privileges;
## 删除账户
drop user myuser;
## 查看权限
show grants for myuser;
## 授予权限
grant select,insert on *.* to myuser;
## 删除权限
revoke select ,insert on *.* from myuser;
## 更改密码
set passowrd for myuser = 'mypass';

存储过程(todo 待完善)

触发器(todo 待完善)

SQL优化

  • 创建索引

  • 执行计划分析

    查看某个sql语句的执行计划只需要在sql语句前面添加EXPLAN

    1
    EXPLAIN select * from person where age = 16 and id > 0;
    1. type:表示执行sql使用了哪种类型。类型从好到差依次是system,const, eq_reg, ref, range, index, ALL
    2. rows:数据遍历的行数,数值越小越好
    3. key_len:使用索引的长度,该值越小越好
    4. key:实际用到的索引,null就是没有
    5. id:相同,执行顺序由上而下;不相同,子查询id序号递增,id值越大优先级越高,越先被执行
    6. select_type:
    7. Ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。
  • sql优化具体分析

    1. 尽量给字段设置默认值,避免字段值为null(如果字段是int类型的age,首先给age创建索引时null不会参与创建索引。where age=0 比where age is null效率高)
    2. 在where语句中少使用or,使用or将不使用索引
      如select name from person where age = 16 or age = 20;
      可以写成:
      select name from person where age = 16 union all select name from person where age = 20;
    3. 在where语句中避免使用in

sql工具

python相关

sqlalchemy-engine

sqlalchemy-mysql

网上的sql资源

图解SQL
138张图带你MySQL入门

互联网公司常用分库分表方案汇总

数据库设计技巧

SQL试题

MySQL

SQL基础知识汇总

常用sql

复制表

1
create table tbA as select * from tbB;

删除表中重复数据

1
delete from vod where id not in (select count(t.id) from (select min(id) as id from vod group by vod_play_url) t)

查询是否有重复数据

1
select vod_play_url from vod group by vod_play_url having count(vod_play_url) > 1;

透明度百分和十六进制互转

A B C D E F
100%[FF] 99%[FC] 98%[FA] 97%[F7] 96%[F5] 95%[F2]
94%[F0] 93%[ED] 92%[EB] 91%[E8] 90%[E6] 89%[E3]
88%[E0] 87%[DE] 86%[DB] 85%[D9] 84%[D6] 83%[D4]
82%[D1] 81%[CF] 80%[CC] 79%[C9] 78%[C7] 77%[C4]
76%[C2] 75%[BF] 74%[BD] 73%[BA] 72%[B8] 71%[B5]
70%[B3] 69%[B0] 68%[AD] 67%[AB] 66%[A8] 65%[A6]
64%[A3] 63%[A1] 62%[9E] 61%[9C] 60%[99] 59%[96]
58%[94] 57%[91] 56%[8F] 55%[8C] 54%[8A] 53%[87]
52%[85] 51%[82] 50%[80] 49%[7D] 48%[7A] 47%[78]
46%[75] 45%[73] 44%[70] 43%[6E] 42%[6B] 41%[69]
40%[66] 39%[63] 38%[61] 37%[5E] 36%[5C] 35%[59]
34%[57] 33%[54] 32%[52] 31%[4F] 30%[4D] 29%[4A]
28%[47] 27%[45] 26%[42] 25%[40] 24%[3D] 23%[3B]
22%[38] 21%[36] 20%[33] 19%[30] 18%[2E] 17%[2B]
16%[29] 15%[26] 14%[24] 13%[21] 12%[1F] 11%[1C]
10%[1A] 9%[17] 8%[14] 7%[12] 6%[0F] 5%[0D]
4%[0A] 3%[08] 2%[05] 1%[03] 0%[00]

adb常用命令

Awesome-ADB

adb服务

启动服务

1
adb start-server

停止服务

1
adb stop-server

设备

1
adb devices

eg: adb -s 47dbxxxxxxxx

1
2
adb -s device_id
adb get-serialno

重启

正常重启

1
adb reboot

重启到bootloader(刷机模式)

1
adb reboot bootloader

重启到recovery(恢复模式)

1
adb reboot recovery

monkey测试

1
2
adb shell monkey -p packagename 1000
adb shell monkey -f /sdcard/xxx.script

查看进程

1
2
3
adb shell ps
adb shell kill pid
adb shell ps -x pid

查看service

1
adb shell service list

查看系统当前内存使用情况

1
2
adb shell cat /proc/meminfo
adb shell dumpsys meminfo package

查看CPU使用情况

1
2
3
4
5
6
7
adb shell top
adb shell top -m 3
adb shell top -m 3 -n 1
adb shell cat /proc/cpuinfo
adb shell cat /proc/stat
adb shell cat /proc/meminfo
adb shell cat /system/build.prop

Activity调试

启动应用

1
2
3
adb shell am start xxx.xxx.xxx/xxx.xxx.xxx.MainActivity
adb shell am start -n packagename/packagename.activity
adb shell am start -n com.android.camera/.Camera

停止目标应用

1
adb shell am start -S com.android.camera/.Camera

带参数传递

1
adb shell am start xxx.xxx.xxx/xxx.xxx.xxx.MainActivity -e argus_name value

启动隐式Intent

-a表示action,-c表示category,-d表示data_uri,-e表示添加额外key-value信息

1
am start -a "android.intent.action.VIEW" -d "https://www.baidu.com" 

启动拨号器拨打10086

1
am start -a android.intent.action.CALL -d tel:10086

播放音频文件

1
am start -a "android.intent.action.VIEW" -t "audio/mp3" -d "file:///storeage/sdcard0/1.mp3"

播放视频文件

1
am start -a android.intent.action.VIEW -d "file:///mnt/sdcard/test.3gp" -t "video/*" 

使用am发送广播

可以在后面添加-e来添加额外信息

1
adb shell am broadcast -a "our.specified.action"

恢复出厂设置

1
adb shell am broadcast -a android.intent.action.MASTER_CLEAR

重启手机

1
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

启动一个服务

1
adb shell am startservice "xxx.xxx.xxx/xxx.xxx.xxx.MyService"

停止应用

1
adb shell am force-stop package

查看当前Activity名称

1
adb shell dumpsys activity | findstr "mFocusedActivity"

启动monitor

监控crash和ANR

1
am monitor

安装apk

安装

1
2
adb install xxx.apk
adb -s xxxx install xxx.apk

覆盖安装

1
adb uninstall -r xxx.apk

卸载应用

卸载

1
adb uninstall package

卸载时保留数据和缓存目录

1
adb uninstall -k package

查看设备应用

查看设备所有应用包名

1
adb shell pm list packages

列出指定包名对应的apk路径

1
adb shell pm path packagename

清空指定包名对应的应用的数据和缓存文件

1
adb shell pm clear packagename

文件管理

1
2
adb push 电脑文件路径 /sdcard
adb pull /sdcard/file 电脑文件路径

删除

-f 强制删除文件不需要确认

-r 递归删除文件夹内文件

-i 删除文件前需要确认

1
adb shell rm /sdcard/text.txt

创建目录

指定 -p递归创建目录

1
adb shell mkdir -p /sdcard/temp/test/

创建文件

1
adb shell touch /sdcard/text.txt

复制文件

1
adb shell cp /sdcard/text.txt /sdcard/test/

移动文件

移动同一目录下文件相当于重命令文件

1
adb shell mv /sdcard/1.txt /sdcard/2.text

input

向屏幕输入一些信息

其中%s表示空格

1
adb shell input text "insert%syour%stext%shere"

模拟屏幕点击事件

1
adb shell input tap 500 14500

模拟手势滑动事件

从屏幕坐标(100,500)开始,滑动到(100,1450)结束,整个过程耗时100ms

1
adb shell input swipe 100 500 100 1450 100

模拟长按操作

也就是两个坐标点相同,耗时超过500ms

1
adb shell input swipe 100 500 100 500 500

模拟点击实体按键的命令

该命令表示调低音量,数字25是KeyEvent类里面定义的一个事件常量,该类定义了将近300个事件常量

1
adb shell input keyevent 25

dumpsys

查看dumpsys能提供的查询服务

1
adb shell service list

常用服务名

activity

ActivityManagerService(AMS相关信息)

package

PackageManagerService(PMS相关信息)

window

WindowManagerService(WMS相关信息)

input

InputManagerService(IMS相关信息)

power

PowerManagerService(PMS相关信息)

prostats

ProcessStatsService(进程统计)

battery

BatteryService(电池信息)

alarm

AlarmManagerService(闹钟信息)

meminfo

MemBinder(内存)

查看电池信息

adb shell dumpsys battery

查看Activity信息

1
adb shell dumpsys activity

直接使用以上命令会得到非常长的信息,一般会选择下面八个命令进行查询

1
2
dumpsys activity intents
dumpsys activity broadcasts(广播)

可缩写成dumpsys activity prov

1
dumpsys activity providers

可缩写成dumpsys activity perm

1
dumpsys activity permissions

可缩写成dumpsys activity s

1
dumpsys activity services
1
dumpsys activity recents

可缩写成dumpsys activity a

1
dumpsys activity activities
1
dumpsys activity processes

如果内容还是太多,可以使用grep过滤

1
adb shell dumpsys activity | grep -i 'run'

查看App有哪些进程

1
adb shell dumpsys activity p com.quark.browser | grep -i 'ProcessRecord' | grep -i 'PID'

查看内存使用情况

1
adb shell dumpsys meminfo com.quark.browser

其他

申请root权限

1
2
adb shell
su

查看手机上所有的包名

1
2
adb shell
cd data/data ; ls

Linux多个命令行一起执行可以用“;”或者“&&” 进行分割

1
cd data/data ; ls

退出

1
exit

屏幕截图

1
adb shell screencap /sdcard/screen.png

录制视频

适用于4.4及以上的设备

1
adb shell screenrecord /sdcard/demo.mp4

bugreport

1
adb bugreport > d:/xxx.log

重定向

执行该命令后所有发往宿主机1314端口的消息、数据都会转发到Android设备的8888端口上,因为可以通过远程的方式控制Android设备

1
adb forward tcp:1314 tcp:8888

列出输入法

1
ime list -s

获取设备分辨率

1
adb shell wm size

查看Android设备的参数信息

1
adb shell getprop 

查看某信息

1
adb shell getprop ro.build.version.sdk

快速创建大文件

1
dd if=/dev/zero of=hello.txt bs=1024000 count=1
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
if =输入文件(或设备名称)。

of =输出文件(或设备名称)。

ibs = bytes 一次读取bytes字节,即读入缓冲区的字节数。

skip = blocks 跳过读入缓冲区开头的ibs*blocks块。

obs = bytes 一次写入bytes字节,即写入缓冲区的字节数。

bs = bytes 同时设置读/写缓冲区的字节数(等于设置ibs和obs)。

cbs = byte 一次转换bytes字节。

count=blocks 只拷贝输入的blocks块。

conv = ASCII 把EBCDIC码转换为ASCIl码。

conv = ebcdic 把ASCIl码转换为EBCDIC码。

conv = ibm 把ASCIl码转换为alternate EBCDIC码。

conv = block 把变动位转换成固定字符。

conv = ublock 把固定位转换成变动位。

conv = ucase 把字母由小写转换为大写。

conv = lcase 把字母由大写转换为小写。

conv = notrunc 不截短输出文件。

conv = swab 交换每一对输入字节。

conv = noerror 出错时不停止处理。

conv = sync 把每个输入记录的大小都调到ibs的大小(用NUL填充)。

查看磁盘使用情况

1
df

打开前置摄像头

1
adb shell am start -a android.media.action.IMAGE_CAPTURE --ei android.intent.extras.CAMERA_FACING 1

打开后置摄像头

1
adb shell am start -a android.media.action.IMAGE_CAPTURE --ei android.intent.extras.CAMERA_FACING 0

SVC命令

设置屏幕的常亮,true保持常亮,false不保持,usb当插入usb时常亮,ac当插入电源时常亮

1
svc power stayon [true|false|usb|ac]  

打开/关闭数据流量

1
svc data enable|disable

打开/关闭wifi

1
svc wifi enable|disable

修改系统配置

1
2
## 修改后,如果没在AndroidManifest做设置,会触发onConfigurationChanged事件
adb shell settings put system font_scale 2.0

开启【调试GPU过度绘制】

1
adb shell setprop debug.hwui.overdraw show

关闭【调试GPU过度绘制】

1
adb shell setprop debug.hwui.overdraw false

ffmpeg常用命令

主要参数

-i 设定输入流

-f 设定输出格式

-ss 开始时间

视频参数

-b 设定视频流量,默认为200kbit/s

-r 设定帧速率,默认为25

-s 设定画面的宽与高

-aspect 设定画面的比例

-vn 不处理视频

-vcodec 设定视频编解码器,未设定时则使用与输入流相同的编码器

音频参数

-ar 设置采样率

-ac 设定声音的Channel数

-acodec 设定声音编解码器,未设定时则使用与输入流相同的编解码器

-an 不处理音频

常用功能

去掉视频中的音频

-an 去掉音频 -vcodec 视频选项,一般后面加copy表示拷贝

1
ffmpeg -i input.mp4 -vcodec copy -an output.mp4

提取视频中的音频

-vn 去掉视频;-acodec 音频选项,一般后面加copy表示拷贝

1
ffmpeg -i 0.blv -f mp3 1.mp3

音视频合成

-y 覆盖输出文件

1
ffmpeg -y -i input.mp4 -i input.mp3 -vcodec copy -acodec copy output.mp4

剪切视频

-ss 开始时间 -t 持续时间

1
ffmpeg -ss 0:1:30 -t 0:0:20 -i input.mp4 -vcodec copy -acodec copy output.mp4

视频截图

-s 设置分辨率 -f 强迫采用格式fmt

1
ffmpeg -i test.mp4 -f image2 -t 0.001 -s 320*240 image-%3d.jpg

视频分解为图片

-r 指定截屏频率

1
ffmpeg -i test.mp4 -r 1 -f image2 image-%3d.jpg

将图片合成视频

1
ffmpeg -f image2 -i image%d.jpg output.mp4

视频拼接

1
ffmpeg -f concat -i filelist.txt -c copy output.mp4

将视频转为gif

-pix_fmt 指定编码

1
ffmpeg -i input.mp4 -ss 0:0:30 -t 10 -s 320*240 -pix_fmt rgb24 output.gif

将视频前30帧转为gif

1
ffmpeg -i input.mp4 -vframes 30 -f gif output.gif

旋转视频

1
ffmpeg -i input.mp4 -vf rotate=PI/2 output.mp4

缩放视频

iw是输入的宽度,iw/2就是一半,-1为保持宽高比

1
ffmpeg -i input.mp4 -vf scale=iw/2:-1 output.mp4

视频变速

1
ffmpeg -i input.mp4 -filter:v setpts=0.5*PTS output.mp4

音频变速

1
ffmpeg -i input.mp3 -filter:a atempo=2.0 output.mp3

音视频同时变速,但是音视频为互倒关系

1
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4

视频添加水印

main_w-overlay_w-10 视频的宽度-水印的宽度-水印边距

1
ffmpeg -i input.mp4 -i logo.jpg -filter_complex [0:v][1:v]overlay=main_w-overlay_w-10:main_h-overlay_h-10[out] -map [out] -map 0:a codec:a copy output.mp4

m3u8转mp4

1
ffmpeg -i "http://cache.utovr.com/201508270528174780.m3u8" -bsf:a aac_adtstoasc -vcodec copy -c copy -crf 50 "1.mp4"
1
ffmpeg -i http://.../playlist.m3u8 -c copy -bsf:a aac_adtstoasc output.mp4

mp4转m3u8

1
ffmpeg -i input.mp4 -profile:v baseline -level 3.0 -s 640x360 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls index.m3u8

将文件按时长分片

1
ffmpeg -i in.mkv -f segment -segment_time 10 -segment_format_options movflags=+faststart out%03d.mp4

文件长度截取

-y 表示如果输出文件已存在则覆盖

1
ffmpeg  -i ./plutopr.mp4 -vcodec copy -acodec copy -ss 00:00:10 -to 00:00:15 ./cutout1.mp4 -y

获取视频的所有帧

1
ffmpeg -i 1.mp4 -q:v 2 -f image2 image%07d.jpeg

其中-i 后面是输入文件,-q:v 2 q代表质量quality, v代表视频流,2是控制质量的参数。-f指定输出的格式是image2. %07d是图片命名的pattern

H264视频转ts视频流

1
ffmpeg -i test.h264 -vcodec copy -f mpegts test.ts

H264视频转mp4

1
ffmpeg -i test.h264 -vcodec copy -f mp4 test.mp4

ts转mp4

1
ffmpeg -i test.ts -acodec copy -vcodec copy -f mp4 test.mp4

mp4转flv

1
ffmpeg -i test.mp4 -acodec copy -vcodec copy -f flv test.flv 

转换文件为3GP格式

1
ffmpeg -y -i test.mpeg -bitexact -vcodec h263 -b 128 -r 15 -s 176x144 -acodec aac -ac 2 -ar 22500 -ab 24 -f 3gp test.3gp

转换文件为3GP格式v2

1
ffmpeg -y -i test.wmv -ac 1 -acodec libamr_nb -ar 8000 -ab 12200 -s 176x144 -b 128 -r 15 test.3gp

使用ffmpeg编码得到高质量的视频

1
ffmpeg.exe -i "D:\Video\Fearless\Fearless.avi" -target film-dvd -s 720x352 -padtop 64 -padbottom 64 -maxrate 7350000 -b 3700000 -sc_threshold 1000000000 -trellis -cgop -g 12 -bf 2 -qblur 0.3 -qcomp 0.7 -me full -dc 10 -mbd 2 -aspect 16:9 -pass 2 -passlogfile "D:\Video\ffmpegencode" -an -f mpeg2video "D:\Fearless.m2v"

转换指定格式文件到FLV格式

1
2
ffmpeg.exe -i test.mp3 -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\test.flv 
ffmpeg.exe -i test.wmv -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\test.flv

转换文件为3GP格式

1
ffmpeg -i test.avi -y -b 20 -s sqcif -r 10 -acodec amr_wb -ab 23.85 -ac 1 -ar 16000 test.3gp

转换文件为MP4格式

1
2
ffmpeg  -y  -i input.wmv  -f mp4 -async 1-s 480x320  -acodec libfaac -vcodec libxvid  -qscale 7 -dts_delta_threshold 1 output.mp4
ffmpeg -y -i source_video.avi input -acodec libfaac -ab 128000 -vcodec mpeg4 -b 1200000 -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s 320x180 -title X final_video.mp4

将一段音频与一段视频混合

1
ffmpeg -i son.wav -i video_origine.avi video_finale.mpg

将一段视频转换为DVD格式

1
ffmpeg -i source_video.avi -target pal-dvd -ps 2000000000 -aspect 16:9 finale_video.mpeg

转换一段视频为DivX格式

1
ffmpeg -i video_origine.avi -s 320x240 -vcodec msmpeg4v2 video_finale.avi

udp视频流的推送

1
ffmpeg -re  -i 1.ts  -c copy -f mpegts   udp://192.168.0.106:1234

视频拼接

裸码流的拼接,先拼接裸码流,再做容器的封装

1
ffmpeg -i "concat:test1.h264|test2.h264" -vcodec copy -f h264 out12.h264

截取一张352x240尺寸大小的,格式为jpg的图片

1
ffmpeg -i test.asf -y -f image2 -t 0.001 -s 352x240 a.jpg

把视频的前30帧转换成一个Animated Gif

1
ffmpeg -i test.asf -vframes 30 -y -f gif a.gif

截取指定时间的缩微图,-ss后跟的时间单位为秒

1
ffmpeg -i test.avi -y -f image2 -ss 8 -t 0.001 -s 350x240 test.jpg

转换wav到mp2格式

1
ffmpeg -i /tmp/a.wav -ab 64 /tmp/a.mp2 -ab 128 /tmp/b.mp2 -map 0:0 -map 0:0

横向流程图源码格式

1
2
3
4
5
6
graph LR
A[方形] -->B(圆角)
B --> C{条件a}
C -->|a=1| D[结果1]
C -->|a=2| E[结果2]
F[横向流程图]

竖向流程图源码格式

1
2
3
4
5
6
graph TD
A[方形] --> B(圆角)
B --> C{条件a}
C --> |a=1| D[结果1]
C --> |a=2| E[结果2]
F[竖向流程图]

标准流程图源码格式

1
2
3
4
5
6
7
8
9
st=>start: 开始框
op=>operation: 处理框
cond=>condition: 判断框(是或否?)
sub1=>subroutine: 子流程
io=>inputoutput: 输入输出框
e=>end: 结束框
st->op->cond
cond(yes)->io->e
cond(no)->sub1(right)->op

标准流程图源码格式(横向)

1
2
3
4
5
6
7
8
9
st=>start: 开始框
op=>operation: 处理框
cond=>condition: 判断框(是或否?)
sub1=>subroutine: 子流程
io=>inputoutput: 输入输出框
e=>end: 结束框
st(right)->op(right)->cond
cond(yes)->io(bottom)->e
cond(no)->sub1(right)->op

UML时序图源码样例

1
2
3
4
5
对象A->对象B: 对象B你好吗?(请求)
Note right of 对象B: 对象B的描述
Note left of 对象A: 对象A的描述(提示)
对象B-->对象A: 我很好(响应)
对象A->对象B: 你真的好吗?

UML时序图源码复杂样例

1
2
3
4
5
6
7
8
9
10
11
Title: 标题:复杂使用
对象A->对象B: 对象B你好吗?(请求)
Note right of 对象B: 对象B的描述
Note left of 对象A: 对象A的描述(提示)
对象B-->对象A: 我很好(响应)
对象B->小三: 你好吗
小三-->>对象A: 对象B找我了
对象A->对象B: 你真的好吗?
Note over 小三,对象B: 我们是朋友
participant C
Note right of C: 没人陪我玩

UML标准时序图样例:**

1
2
3
4
5
6
7
8
9
10
11
12
%% 时序图例子,-> 直线,-->虚线,->>实线箭头
sequenceDiagram
participant 张三
participant 李四
张三->王五: 王五你好吗?
loop 健康检查
王五->王五: 与疾病战斗
end
Note right of 王五: 合理 食物 <br/>看医生...
李四-->>张三: 很好!
王五->李四: 你怎么样?
李四-->王五: 很好!

甘特图样例:**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%% 语法示例
gantt
dateFormat YYYY-MM-DD
title 软件开发甘特图
section 设计
需求 :done, des1, 2014-01-06,2014-01-08
原型 :active, des2, 2014-01-09, 3d
UI设计 : des3, after des2, 5d
未来任务 : des4, after des3, 5d
section 开发
学习准备理解需求 :crit, done, 2014-01-06,24h
设计框架 :crit, done, after des2, 2d
开发 :crit, active, 3d
未来任务 :crit, 5d
耍 :2d
section 测试
功能测试 :active, a1, after des3, 3d
压力测试 :after a1 , 20h
测试报告 : 48h

Rxjava使用讲解

使用Rxjava进行输入框搜索

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
Observable.just(keyword)
//EditText内容输入后,500毫秒后才发送事件
.debounce(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
//过滤掉空字符串
.filter(text -> !TextUtils.isEmpty(text))
//保证发送的数据是最新的
.switchMap((Function<String, Observable<CommonResp<List<SchoolPojo>>>>) text -> query(text.trim()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
.subscribe(new BaseCommonObserver<CommonResp<List<SchoolPojo>>>() {
@Override
protected void onError(String error) {
ToastUtils.showShortToast("网络异常");
relatedSearchAdapter.setNewData(Collections.EMPTY_LIST);
showRelatedSearchRv();
}

@Override
protected void onSuccess(CommonResp<List<SchoolPojo>> data) {
if (CollectionUtils.isListEmpty(data.getData())) {
relatedSearchAdapter.setNewData(Collections.EMPTY_LIST);
} else {
relatedSearchAdapter.setNewData(data.getData());
}
showRelatedSearchRv();
}
});

Single/Maybe/Completable

Single:只发送一个事件:onSuccess(T t)或者onError(Throwable e),适合网络请求,

Completable:不关心数据,只关心结果,只有onComplete()和onError(Throwable e)方法,通常会配合andThen一起使用

Maybe: 发送0个或1个事件,onSuccess(T t)/onError(Throwable e)/onComplete()

combineLatest

combineLatest()和zip()都是对observableA和observableB按照Func2中制定的规则进行组合,二者最大的不同在于,zip()的组合顺序是observableA和observableB中的元素有一一对应的关系,相同位置的元素按照Func2中制定的规则进行组合,combineLatest()就没有这种所谓的一一对应的关系,而是observableA或者observableB发射一个元素时,这个元素会向前去寻找另一个observable发射出来的元素,直到寻找到一个为止,然后再按照Func2中制定的规则进行组合

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Observable<List<Entry>> purpleFeedObservable =
FeedObservable.getFeed("https://news.google.com/?output=atom");
Observable<List<Entry>> yellowFeedObservable =
FeedObservable.getFeed("http://www.theregister.co.uk/software/headlines.atom");

Observable<List<Entry>> combinedObservable = Observable.combineLatest(purpleFeedObservable, yellowFeedObservable,(purpleList, yellowList) -> {
final List<Entry> list = new ArrayList<>();
list.addAll(purpleList);
list.addAll(yellowList);
return list;
}
);

combinedObservable.observeOn(AndroidSchedulers.mainThread()).subscribe(this::drawList);

zip

zip(observableA, observableB, Func2)用来合并两个Observable对象发射的数据项并合成一个新Observable对象,根据Func2函数生成一个新的值并发射出去,在这里Func2就相当于observableA和observableB的合并规则,当其中一个Observable对象发送数据结束或者出现异常后,另一个Observable对象也将停止发射数据。

img

Merge

merge(Observable, Observable)将两个Observable发射的事件序列组合并成一个事件序列,就像是一个Observable发射的一样。你可以简单的将它理解为两个Observable合并成了一个Observable,合并后的数据是无序的。

img

startWith

startWith(T)用于在源Observable发射的数据前插入数据。使用startWith(Iterator)我们还可以在源Observable发射的数据前插入Iterator。

img

Concat

concat(Observable<? extends T>, Observable<? extends T>)和concat(Observable<? extends Observable>)用于将多个Observable发射的的数据进行合并发射,concat严格按照顺序发射数据,前一个Observable没发射玩是不会发射后一个Observable的数据的。它和merge、startWitch和相似,不同之处在于merge合并后发射的数据是无序的,startWitch只能在源Observable发射的数据前插入数据,而concat是在另一个Observable上进行合并并且合并的发射数据是有序的。

img

onErrorReturn

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
Observable.just(1)
.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return null;
}
}).onErrorReturn(new Function<Throwable, String>() {
@Override
public String apply(Throwable throwable) throws Exception {
System.out.println("onErrorReturn--->" + throwable.getMessage());
//如果正常返回,那么不会走onError逻辑,只会走onNext逻辑
return "";
//如果返回null或者抛出异常,那么会走onError逻辑,不会走onNext逻辑
//throw new Exception("11");
//return null;
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onNext(String s) {
System.out.println("onNext--->" + s);
}

@Override
public void onError(Throwable e) {
System.out.println("onError--->" + e.getMessage());
}

@Override
public void onComplete() {

}
});

flatMap

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Flowable.fromIterable(MockData.getAllStudentInfoById(0))
.flatMap(new Function<Student, Publisher<Source>>() {
@Override
public Publisher<Source> apply(@NonNull Student student) throws Exception {
return Flowable.fromIterable(student.mSources);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Source>() {
@Override
public void accept(@NonNull Source source) throws Exception {
String content = "sourceName:"+source.name +" source score:"+source.score;
mTextView.setText(content);
Log.i(TAG,content);

}
});

img

Compose

使用一个Transformer将一种类型的Observable转换为另一种类型Observable.通过compose我们可以实现一系列操作符的复用,并且还可以保证链式调用不被打断

1
2
observable.subscribeOn(Schedulers.io).observerOn(AndroidSchedulers.mainThread())