Fork me on GitHub
夸克的博客


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

并发编程——Thread API

发表于 2019-02-21 | 分类于 并发编程 , 并发基础 | 热度: ℃
字数统计: 3,073 | 阅读时长 ≈ 12

这篇主要介绍Thread API,也是并发编程中的基础

阅读全文 »

索引优化和设计原则

发表于 2019-02-02 | 分类于 mysql | 热度: ℃
字数统计: 1,085 | 阅读时长 ≈ 4

索引的优化原则

  1. 联合索引尽量所有字段全值匹配。如果使用部分字段,注意最左前缀规则,按照顺序使用联合索引。
  2. 不在索引列上做计算、函数、类型转换等操作,会导致索引失效走全表扫描。
  3. 尽量使用索引覆盖,减少select * 带来的回表的成本。
  4. mysql使用in、not in、is null、is not null、<> 、 !=,mysql的优化器会根据扫描的条数进行成本分析,可能直接会全表扫描,所以注意查询条件命中记录的条数。
  5. like注意使用前缀通配匹配。like ‘abc%’。如果没办法可要优化到索引覆盖级别。
  6. 如果不符合预期,可以强制force index使用索引。
  7. 避免文件排序(explain extra中有Using filesort)。为排序字段建立索引,或者where条件字段和排序字段能使用联合索引。排序还要避免多个排序字段的升序、降序规则不同。

如果不能避免filesort,则可以调整mysql的参数max_length_for_sort_data,调小一点来触发双路排序。filesort是在内存维护一个sort buffer,当要排序字段总大小大于这个值就会在buffer中只加载主键和排序字段,回表拿最后的结果,而不是在buffer中加载所有符合条件的数据的所有字段排序后返回。

  1. 分页优化
    1
    select * from table where name ='xxx' limit 100000,10;

此语句的过程是,扫描二级索引name,查出符合条件的主键值,回表查询聚簇索引,扫描100010行,取最后的10行。

深度分页会造成回表扫描大量聚簇索引才能取到深度的那几条数据,造成效率低下。

解决办法:

  • 能用主键先用一个标签来过滤的场景来用主键id过滤。
    改写为
    1
    select * from table where id > 100000 limit 10;

这样能减少扫描聚簇索引的数量。但是有局限性,因为要求能找到这样一个标签值,且结果是按照主键这样排序的。

  • 非主键排序的深度分页可以用延迟关联的方法来连接查询。
    1
    select * from table order by name limit 100000,5;

可以改写为

1
select * from table a where inner join (select id from table b order by name limit 100000, 5) b on a.id = b.id;

这样的连接查询中,子查询先是索引覆盖去排序去筛选出对应的记录且去除分页记录,然后再作为驱动表连接查询该表,此时是根据主键id做关联查询,可以大量减少回表扫描记录数。

  1. 连接查询的优化
  • 连接查询的字段建立索引,驱动表记录去和被驱动表连接查询可以使用索引。
  • 小表驱动大表,本身连接查询也是这样去选择驱动表的。
  • 连接字段没有索引,mysql本身会有一个基于块的嵌套循环查询算法,在内存中有join_buffer区域去加载一批驱动表的数据,去和被驱动表做关联查询,减少磁盘IO的次数。
  1. count查询
  • count(字段) 不为统计null的记录数。count(id)、count(1)、count(*)会统计null的记录。
  • 本身这几个效率差不多,在count(字段)中的字段有索引情况下,可以直接扫描二级索引来完成统计,效率更高。

索引的设计原则

  1. 代码先行,索引后上
    因为代码中要开发sql查询,可以根据业务中的sql来确定具体的sql来建立合适的索引。

  2. 联合索引进来覆盖条件

索引要能覆盖大量查询场景(where、order by、group by),顺序也要按照最左前缀原则来设计。

  1. 不要在小基数的字段上建立索引

越小的基数在等值或者范围查询场景下扫描更多的记录,可能造成优化器选择全表扫描。 不能发挥索引的优势。

  1. where 和order by 冲突 尽量先满足where
  2. 索引字段的长度尽量小一点,相同大小空间的B+树能承载更多的数据,查找效率也更高。

设计模式——模板方法的应用

发表于 2019-02-01 | 分类于 设计模式 | 热度: ℃
字数统计: 977 | 阅读时长 ≈ 4

模板方法

模板方法

很多情况下代码中的业务都可以抽象出一个模板去解决,这时候经常需要用到模板方法。大家经常接触到的是一些业务方法的抽象模板,比如在计算优惠券的流程当中总是有一定的步骤:

(1)先计算该商品是否可以拥有优惠券信息

(2)再为该商品绑定优惠券信息

(3)最后回调或者通知向下的流程

今天要记录的是一个通用服务层的模板方法,包含了前置校验、后置处理(是有点像拦截器= =)、finally操作。

业务processor

  1. 可以定义一个domainProcessor去代表业务操作的processor接口,这个接口可以承接泛型。
1
2
3
4
5
6
7
8
9
public interface DomainProcessor<T> {

/**
* 处理业务的方法 返回值现在是void的 也可以自己定义一个通用的类似于上下文的返回值
*
* @param context
*/
void process(T context);
}

这里承接的泛型context是一个上下文的概念,指的是在一个业务处理processor中的上下文信息,其中可以有计算的参数,计算的结果和一些中间信息。

  1. 做一个抽象类,去将其中的前置操作、biz操作、后置操作、finally操作定义出来。
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
62
63
64
65
66
public abstract class AbstractProcessor<T> implements DomainProcessor<T> {

/**
* 前置处理 主要做一些校验逻辑 编排的时候放在前边
*
* @param context
* @return
*/
protected boolean preHandle(T context){
return true;
}

/**
* 业务处理 这个是抽象方法 子类去实现具体的逻辑
* @param context
*/
protected abstract void bizHandle(T context);

/**
* 后置处理
*
* @param context
*/
protected void postHandle(T context) {
}

/**
* last 操作
* @param context
*/
protected void finallyHandle(T context) {
}

/**
* 异常处理
*
* @param context
* @param e
*/
protected void exceptionHandle(T context, Exception e) {
// TODO 打印error或者warn级别日志
throw new BizException(e.getMessage(), e);
}

@Override
public void process(T context) {
/**
* 编排流程
*/
try {
if (!preHandle(context)) {
// log.warn("处理器前置处理失败,退出。context:{}", context);
return;
}
// 业务方法
bizHandle(context);
// 后置操作
postHandle(context);
} catch (Exception e) {
exceptionHandle(context, e);
} finally {
finallyHandle(context);
}
}

}

可以看到,这里定义了前置操作,这里可以去对biz要用的参数进行一个校验或者一些前置操作,同时将biz定义为了抽象方法,意图在为了让子类去继承时一定要去实现bizHandle这个方法。而exceptionHandle和finallyHandle方法则定义了异常的处理和最终要做的(比如线程快照的清除)。而整个process方法其实就是整个处理器的入口,即对这整个流程的一个编排。

可以看一个这个模板processor的的具体实现和测试类:

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
public class AbstractProcessorTest {

private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

public static void main(String[] args) {
// TODO test
TestContext testContext = new TestContext();
contextHolder.set("aaa");
TestProcessor testProcessor = new TestProcessor();
// 调用process的编排
testProcessor.process(testContext);

TestContext exContext = new TestContext();
// test bizHandle
testProcessor.process(exContext);
}

private static class TestProcessor extends AbstractProcessor<TestContext> {
@Override
protected boolean preHandle(TestContext context) {
// 前置的一个check或者一个前置操作
String s = contextHolder.get();
if (s == null) {
throw new RuntimeException("holder中字符串为空");
}

context.setMessage(s);
return true;
}

@Override
protected void postHandle(TestContext context) {
context.setPostStr("post");
System.out.println("processor 结果是:"+ context.isResult());
}

@Override
protected void finallyHandle(TestContext context) {
if (context.isResult()) {
contextHolder.remove();
}
}

@Override
protected void bizHandle(TestContext context) {
context.setResult(context.getMessage().length()>0);
}
}
}

总结

这个模板可以作为之后一个处理器的抽象模板,能让代码逻辑很清晰的展现出来,也能解耦了各个处理模块,这里可以总结下。

并发编程——基础拾遗

发表于 2018-12-31 | 分类于 并发编程 , 并发基础 | 热度: ℃
字数统计: 1,701 | 阅读时长 ≈ 7

并发编程基础拾遗

在看并发的书或者看并发相关的博客时,会发现一些知识点会遗漏或者之前没有看到,这里去总结一下。

阅读全文 »

设计模式——观察者模式

发表于 2018-12-24 | 分类于 设计模式 | 热度: ℃
字数统计: 3,653 | 阅读时长 ≈ 17

观察者模式

观察者模式也是我们经常会用到的设计模式之一,这里用一个气象站的一些数据变化通知气象板为例去记录一下观察者设计模式,值得一提的是java中提供了观察者模式的接口和类。

阅读全文 »

test多个设备使用hexo

发表于 2018-12-24 | 分类于 hexo | 热度: ℃
字数统计: 30 | 阅读时长 ≈ 1

背景

hexo是支持多设备去写你的博客的,这里参考的是这个资料:

hexo多设备

集合中的深拷贝

发表于 2018-12-19 | 分类于 Java基础 | 热度: ℃
字数统计: 2,289 | 阅读时长 ≈ 10

深拷贝与浅拷贝

对对象的深拷贝和浅拷贝我们并不陌生。

阅读全文 »

java集合类的一些总结——Arrays.asList和Guava操作集合

发表于 2018-12-15 | 分类于 Java基础 | 热度: ℃
字数统计: 1,178 | 阅读时长 ≈ 5

使用背景

总结一下最近项目中使用到集合的两个点,一个是Arrays.asList这个方法使用的坑,另一个是利用Guava的Sets工具类去求并交集。

阅读全文 »

ClassNotFoundException和NoClassDefFoundError

发表于 2018-12-06 | 分类于 Java基础 | 热度: ℃
字数统计: 934 | 阅读时长 ≈ 3

背景

极客时间上《Java核心技术36讲》第二讲中提到了一个问题:ClassNotFoundException和NoClassDefFoundError有什么区别?看到这个问题的时候,第一时间想到的就是一个是受检的异常,而另一个是一个Error,但是其实在真正的项目开发中这两个错误都遇到过,都是关于类或者文件jar包找不到的错误,这里去总结下其中的不同。

阅读全文 »

java平台与java是解释执行的正确性

发表于 2018-11-30 | 分类于 Java基础 | 热度: ℃
字数统计: 1,020 | 阅读时长 ≈ 4

背景

最近看了一点点极客时间上的《Java核心技术36讲》,打算把一些自己感兴趣或者不知道的点总结到博客中,方便对一些知识有一些整理和拾遗。

阅读全文 »
1…8910…12
夸克

夸克

愿赌服输

114 日志
32 分类
121 标签
GitHub E-Mail csdn
© 2022 夸克 | Site words total count: 168.9k
|
主题 — NexT.Muse v5.1.4
博客全站共168.9k字

载入天数...载入时分秒...