mysql的日志
binlog
redo log
undo log
WAL(Write-Ahead Log)
JVM Reference
引用
java有四种引用:强引用、软引用、弱引用、虚引用、
InnoDB SQL分析
语法
DDL语法
-- 新增列
ALTER TABLE student ADD COLUMN `class_id` int(11) DEFAULT NULL COMMENT '班级id' after `student_name`;
-- 修改列
ALTER TABLE student MODIFY COLUMN `class_name` varchar(20) DEFAULT NULL COMMENT '班级名称';
-- 新建索引
ALTER TABLE student ADD INDEX idx_class_id(class_id);
-- 创建表时,带索引
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '代理自增主键',
`config_id` int(11) NOT NULL COMMENT '配置id',
PRIMARY KEY (`id`),
KEY `idx_config_id` (`config_id`),
KEY `idx_other_id` (`other_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置表';
-- update 错误写法
update student set age = 1 and student_name = 'lilei' where id = 1;
-- 上述sql意思是:age值是bool表达式,如果name是lilei,则age=1,否则age=0
update student set age = (1 and student_name = 'lilei') where id = 1;
-- update正确写法
update student set age = 1, student_name = 'lilei' where id = 1;
-- select错误写法(sql5.6不报错class_name随机,sql5.7报错,sql8报错)
select class_id, count(id), class_name from student group by class_id;
-- select正确写法
select class_id, count(id), class_name from student group by class_id, class_name;
explain
explain select * from student where id = 10
上述sql执行结果如下:
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | student | NULL | const | PRIMARY | PRIMARY | 8 | const | 1 | 100.00 | NULL |
字段 | 含义 |
---|---|
id | 数字越大越优先执行,如果数字一样大,从上到下执行 |
select_type | simple表示不用union或不包含子查询,还有union、subquery |
table | 查询表名,如果用到别名,则显示别名 |
partitions | 使用分区表时出现 |
type | 后面详细说明 |
possible_keys | 查询可能使用到的索引,都列出来 |
key | 真正使用的索引 |
key_len | 用于处理查询的索引长度 |
ref | 如果使用常数等值查询,则显示const,如果是连接查询,则被驱动表的这个位置 显示驱动表的关联字段 |
rows | 预估扫描行数,越小越好 |
filtered | 存储引擎返回的数据在server层过滤后,剩下多少满足查询要求的记录数据比例,越大越好。 |
Extra | using filesort、using index、using join bugger、using union、using temporary、using where |
Extra说明:filesort,说明要在server层做一次额外排序
type字段类型 | 含义 |
---|---|
ALL | 全表扫描 |
index | 扫描全索引 |
range | 索引,范围<> |
ref | 索引查找,匹配单值 |
const | 主键或唯一索引,只匹配一行数据 |
方向:
- 利用索引,减少数据扫描范围,减少排序
- 避免不正确、低效、复杂的sql
- 防止单表容量、流量多大,设计要合理
- 使用其他手段比如缓存、其他引擎、业务逻辑优化
优化
- 不能在索引上做运算,比如
select * from user where id + 1= 10
,不会走索引。 - 查询类型要一致,否则不走索引。比如,一个字段是字符串类型,如果执行
where number = 123
,实际执行的是where cast(number as int) = 123
,这时候不走索引, - 避免使用前缀匹配模糊查询
- 慎用count,
count(1) = count(*) = count(id)
,如果name有空值,则count(1) != count(name)
- 不写复杂sql
- limit偏移量不要写过大,
- 避免负向查询:not、!=、<>、!<、!>、not exists、not in、not like等
并发控制
并发控制机制有两种实现:锁 和 MVCC(Multi-Version Concurrency Control多版本并发控制) 对于读多写少的场景,采用MVCC更合适,每个数据项都有多个副本,每个副本都有一个时间戳,根据协议内容,维护各版本。 乐观锁:读取数据项时,不加锁(乐观的认为不会有冲突),在更新时,知道最后提交才会检查冲突。这么做是为了提高并发度。为了方式ABA问题,引入版本号的概念。其实现就是MVCC,类似于CAS。 悲观锁:适用于读少写多的场景,悲观的认为修改会有冲突,因此通过锁来解决问题。
书籍推荐 MySQL必知必会 https://book.douban.com/subject/3354490/ 高性能MySQL(5.5) https://book.douban.com/subject/23008813/ MySQL技术内幕InnoDB存储引擎 https://book.douban.com/subject/24708143/
JAVA WEB开发好用的工具
插件
1 依赖包使用maven管理,推荐使用Maven Helper插件,如果是命令行大佬,可以忽略。
Http接口返回数据的一些问题
概述
端午节跟游顺一起做了个小web系统,有账户模块和查询模块两部分。本来说三天做完这个初版的功能,但是仅账户登录就已经把我的时间耗尽了,也就没时间做查询了。登录用的Spring Security实现jwt认证,期间翻看过Spring文档和一篇博客,基本上还原出来了,也知道大概的原理。想说的不是这个登录,登录还没时间吃透。想说的是关于http接口请求的返回数据。
问题
SpringBoot接口返回数据极其简单,定义好一个对象,就可以返回对象格式的json了,甚至可以单纯返回字符串。
但是如果用HttpServletResponse
对象如何操作呢?问题场景是,有时候在filter
里就想返回请求结果。
如果想改变接口返回的HttpCode,又怎么做呢?场景是,有时候前端RD想用HttpCode做判断,而非一个正常的Http返回结果,需要判断返回数据中的某个字段。详见这里
解决方法
不多废话了,直接贴代码吧
import com.jiler.website.responseData.ResponseData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 返回对象
*
* @return
*/
@GetMapping("/info")
public ResponseData<String> userInfo(){
ResponseData<String> responseData = new ResponseData<>();
responseData.setData("wujunpeng");
return responseData;
}
/**
* 返回字符串
*
* @return
*/
@GetMapping("/name")
public String userName(){
return "wujunpeng";
}
/**
* 用response对象返回
*/
@RequestMapping(value = "/alive", method = RequestMethod.GET)
public void monitorAlive(HttpServletResponse response) throws IOException {
Map<String, Object> result = new HashMap<>();
result.put("status", 0);
result.put("message", "执行完毕");
response.setContentType("text/html;charset=utf-8");
response.getWriter().print(MyJsonUtils.toJson(result));
}
/**
* 用response对象修改HttpCode
*/
@GetMapping("/password")
public void password(HttpServletResponse response) throws IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "禁止请求密码接口");
// response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 用这个也行。
}
}