Fork me on GitHub

为什么要使用Spring IOC?

图片来自https://www.zoltanraffai.com/blog/inversion-of-control-container/

作者:valarchie 的技术小屋

链接:https://juejin.im/post/5d78a9f1e51d453b1f37ebb6

来源:掘金

小结:

  • 控制反转(IOC):
    • 控制:上层需要去控制 new 下层对象
    • 反转:反转意味着我们把对象创建的控制权交出去,交给 IOC 容器,由 IOC 容器负责创建特定对象,并填充到各个声明需要特定对象的地方
  • 依赖注入(DI):通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。
  • IOC 和 DI 的区别:IOC 是目的,DI 是手段。其实 IOC 相当于接口,它规定了要实现什么?而依赖注入(DI)就是具体的实现

使用 IOC 的好处:

  1. Bean 之间的解耦,这种解耦体现在我们没有在代码中去硬编码 bean 之间的依赖。(不通过 new 操作依次构建对象,由 springIOC 内部帮助我们实现了依赖注入)。一方面,IOC 容器将通过 new 对象设置依赖的方式转变为运行期动态的进行设置依赖。
  2. IOC 容器天然地给我们提供了单例。
  3. 当需要更换 dao 的时候,我们只需要在配置文件中更换 dao 的实现类,完全不会破坏到之前的代码。
  4. 上层现在不需要知道下层是如何创建的。

IOC 容器实现了开发中对象粒度的一种组件化,将每个对象当做组件一样放进容器当中。而每个组件都是可插拔,这种是最佳的对象解耦方式。一方面通过将对象之间的耦合关系从编译期推迟到运行期。一旦有需要这个对象的话,就直接使用,客户程序员完全不需要知道这个对象的来龙去脉。并且 IOC 容器对 Bean 的统一管理使得 AOP 的实现更加的方便。

1. 思考

Spring 已经占据我们 Java 开发框架中的半壁江山了,从一开始工作我们就在使用 Spring。但是到底为什么要用 Spring,可能很多人都没有去思考过这个问题?许多人可能也疲于应对需求,无暇思考这种看似理所当然的问题。那今天,我们就好好来讨论一下究竟为什么要使用 Spring IOC?

2. 逆向思考

假设在最初没有 Spring IOC 这种框架的时候,我们采用传统 MVC 的方式来开发一段常见的用户逻辑。

用户 DAO

1
2
3
4
5
6
7
8
9
10
11
12
public class UserDAO {

private String database;

public UserDAO(String dataBase) {
this.database = dataBase;
}
public void doSomething() {
System.out.println("保存用户!");
}

}

用户 Service

1
2
3
4
5
6
7
8
9
10
11
12
public class UserService {

private UserDAO dao;

public UserService(UserDAO dao) {
this.dao = dao;
}
public void doSomething() {
dao.doSomething();
}

}

用户 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Controller {

public UserService service;

public Controller(UserService userService) {
this.service = userService;
}

public void doSomething() {
service.doSomething();
}

}

接下来我们就必须手动一个一个创建对象,并将 dao、service、controller 依次组装起来,然后才能调用。

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {

UserDAO dao = new UserDAO("mysql");
UserService service = new UserService(dao);
Controller controller = new Controller(service);

controller.doSomething();

}

分析一下这种做法的弊端有哪些呢?

  1. 在生成 Controller 的地方我们都必须先创建 dao 再创建 service 最后再创建 Controller,这么一条繁琐的创建过程。
  2. 在这三层结构当中,上层都需要知道下层是如何创建的,上层必须自己创建下层,这样就形成了紧密耦合。为什么业务程序员在写业务的时候却需要知道数据库的密码并自己创建 dao 呢?不仅如此,当如果 dao 的数据库密码变化了,在每一处生成 Controller 的地方都需要进行修改。
  3. 通过 new 关键字生成了具体的对象,这是一种硬编码的方式,违反了面向接口编程的原则。当有一天我们从 Hibernate 更换到 Mybatis 的时候,在每一处 new DAO 的地方,我们都需要进行更换。
  4. 我们频繁的创建对象,浪费了资源。

这时候我们再来看看如果用 SpringIOC 的情况,刚才的代码变成如下。

1
2
3
4
5
6
7
public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
Controller controller = (Controller) context.getBean("controller");
controller.doSomething();

}

很明显,使用 IOC 之后,我们只管向容器索取所需的 Bean 即可。IOC 便解决了以下的痛点:

  1. Bean 之间的解耦,这种解耦体现在我们没有在代码中去硬编码 bean 之间的依赖。(不通过 new 操作依次构建对象,由 springIOC 内部帮助我们实现了依赖注入)。一方面,IOC 容器将通过 new 对象设置依赖的方式转变为运行期动态的进行设置依赖。
  2. IOC 容器天然地给我们提供了单例。
  3. 当需要更换 dao 的时候,我们只需要在配置文件中更换 dao 的实现类,完全不会破坏到之前的代码。
  4. 上层现在不需要知道下层是如何创建的。

通过这个例子可能读者有点若有所思了,那我们再来看一下 IOC 的定义是什么。

3. 定义

控制反转(Inversion of Control,缩写为 IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称 DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

4. 解读

控制反转,控制体现在什么地方?控制就体现在我们一开始的例子,上层需要去控制 new 下层对象。而反转意味着什么呢? 反转意味着我们把对象创建的控制权交出去,交给谁呢?交给 IOC 容器,由 IOC 容器负责创建特定对象,并填充到各个声明需要特定对象的地方。同学们可能会对 IOC 和 DI 觉得很绕,其实 IOC 相当于接口,它规定了要实现什么?而依赖注入(DI)就是具体的实现,它实现了 IOC 想要的效果。IOC 的思想很好地体现了面向对象设计法则之一——好莱坞法则:“别找我们,我们找你”;即由 IoC 容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

如何减低耦合?我们举个例子,当在 IDEA 开发环境中我们添加插件的时候,却需要去知道该插件需要什么依赖,要怎么才能成功开启插件?是不是对用户相当不友好呢?既然我们要使用插件,意味着我们和插件之间是耦合的,无法避免。但是如果我们还需要知道插件需要的依赖和开启插件的步骤,说明我们和插件之间的耦合关系更强烈了。所以 SpringIOC 的定义当中写道“降低耦合”而非“消除耦合”,但只要耦合度降低的话,就有利于代码的维护和扩展。思考一下?是不是跟 Maven 的机制很类似呢?在 Maven 中声明依赖的话,Maven 的自动将该依赖所需的其他依赖递归的寻找。你可以把你自己想象成一个对象的设计师,你设计了一张对象内部构造的图纸,交给 SpringIOC,它会自动地根据这份图纸生成这个对象。

IOC 容器实现了开发中对象粒度的一种组件化,将每个对象当做组件一样放进容器当中。而每个组件都是可插拔,这种是最佳的对象解耦方式。一方面通过将对象之间的耦合关系从编译期推迟到运行期。一旦有需要这个对象的话,就直接使用,客户程序员完全不需要知道这个对象的来龙去脉。并且 IOC 容器对 Bean 的统一管理使得 AOP 的实现更加的方便。这样一来,我们客户程序员就可以更专注在业务代码的编写上。

HTTP API的6种设计原则

原文地址:https://medium.com/@aldesantis/6-design-principles-for-your-http-apis-560434f9744e

作者:Alessandro Desantis

翻译:高行行

良好的API设计是一门艺术,这一点没有争议。当我们遇到一个经过适当设计的API时,我们会感觉到。就像良好的视觉UI一样,良好的API不仅美观,而且功能强大并且可以节省每个人的时间。基于这种想法,可以说API实际上就是UI。它们也不仅仅适用于机器:由于有人在编程和使用这些机器,因此创建一个用户感到高兴与之交互的API是其开发团队的明智选择,我们应该做出选择。

关于视觉UI的设计原理,有很多资源,也有很多可以从中得到启发的好例子。另一方面,涉及API时,有很多文档说明了用于实现这些协议的不同协议,语言和框架,但是几乎没有足够的材料来说明使某些API易于使用和使用的基本原理和选择。别人的噩梦。

尽管没有什么能比以往更胜一筹,并且每个团队都针对API的出色之处制定了自己的规则,但我们可以通过在API设计中应用一些基本原则来从中受益。这些非常抽象,可以用许多不同的方式实现,但它们应始终指导我们的技术决策。

1. 一致性

一致性意味着相似的端点应该以相似的方式运行,包括在边缘场景中。您应该始终努力在整个API中保持词汇表,URL结构,请求/响应格式和错误处理的一致性。

这提供了几个好处:

  • 它使与您的API的交互变得更加简单,因为用户始终知道期望什么,而不必阅读每个端点的文档,而可以随心所欲。
  • 它允许编写客户端库,这些客户端库不知道API的确切架构,仅知道您遵守的规则。Stripe API客户端就是一个很好的例子:由于请求和响应的结构始终相同,因此它可以动态构建对象,并且仅在其中一个API规则更改时才需要更新。
  • 它创建了一组经过实践检验的准则,在API中实现新功能时可以遵循这些准则。不再讨论使用数字ID还是UUID,因为您将继续使用已有的东西。

一致性可能是您可以在API设计中实现的最有影响力的特征,并且您的用户会因此而爱您。

2. 性能

HTTP API的性能非常棘手。由于最终用户不会直接使用API,因此很容易很长时间就不会注意到性能问题,尤其是在服务器到服务器交互的情况下。不幸的是,由于软件是为人开发的,因此所有类型的性能问题最终都会影响最终用户。

出于通常的原因,我强烈建议您不要进行早期优化:这会减慢MVP的开发速度,并且如果不首先制定正确的指标,就无法知道需要优化产品的哪些部分。您应该基于数据而非本能进行优化。

如此说来,从第一天开始收集数据就非常重要。如今,设置APM工具只需几秒钟,它将为您提供大量有关在现实世界中如何使用API的有用信息。

3. 文献资料

不管您的API多么一致,用户仍然需要他们可以去的地方才能开始使用或获得有关API某些方面或功能的其他详细信息。

此外,API文档不应该只是呈现请求和响应模板。建议添加可能对用户有用的任何信息,例如有关在进行某个API调用时在后台发生的情况或用户可能需要完成其他交易的其他终结点的解释,这是有用的。

API文档的准确性和最新性非常重要。实现此目的的唯一方法是创建工作流,以将文档集成到开发过程中。一个好的方法是将文档检入VCS,并要求开发人员在更改API时对其进行更新。

让开发人员编写文档似乎是浪费时间,但是花在文档上的时间越多,花在回答问题和调查虚假错误报告上的时间就越少。

最后,确保不仅提供文档,而且请查阅。由于它是供人类食用的,因此在阅读文档时要特别注意UI和UX。无需您自己执行此操作,您只需采用Stoplight之类的服务即可为您存储和呈现标准格式的内容。

4. 易用性

虽然在数据库表和API资源之间建立1:1映射并不是天生的错误,但是您应该知道,这不是构建API的唯一方法。实际上,对于复杂的API而言,这通常不是最佳方法,因为这使按正确顺序将正确的一组操作组合在一起的所有负担都落在了用户的肩膀上。

如果您可以简化业务交易以仅需要一个API调用而不是两个API调用,为什么不这样做呢?视觉UI要求在后台发生的每个操作都需要用户输入是不可想象的-但是,当我们要求用户出于懒惰而做时,这正是我们在许多API中所做的。

API的一个示例就是该API,它允许用户添加新的付款方式并将一种付款方式标记为默认付款方式。如果我们希望用户希望添加新方法并立即将其标记默认属性,则可以向支付方法创建端点添加标记默认属性,并在一次交易中完成所有操作,而无需两次API调用。这样既节省了开发时间,又节省了带宽。

这种简化并非总是可能的:当您无法预先确定API的确切用例时(例如,在使用公共API的情况下),则应该尽可能地灵活(在上面的示例中,这意味着要添加该字段,还要维护一个单独的端点来设置默认付款方式)。

经验法则是将API的各个方面视为达到目的的手段,即完成业务流程。您如何最好地帮助用户实现该目标?一旦考虑到这一点,设计选择就会变得更加容易。

5. 简单

在简单的,通用的标准和工具之上构建您的API。除非您有充分的理由使用信封,否则不需要信封,架构,API网关或任何其他深奥的解决方案。

HTTP RFC已经为您提供了构建可靠且可互操作的Web服务所需的大多数工具,因此请继续阅读它(是的,虽然很长,但是我可以保证值得)。

坚持基础并做好。简单意味着对人和机器的开销更少,并且出错的空间也更少。例如,以下是使用Stripe API向信用卡收费的方法:

1
2
3
4
5
6
curl https://api.stripe.com/v1/charges \ 
-u your_api_key: \
-d amount=999 \
-d currency=usd \
-d description="Example charge" \
-d source=tok_visa

它是如此简单,您无需查找文档即可进行操作,并且几乎不可能将其弄乱。这是您要争取的简单性。

(顺便说一下,Stripe API是周到的API设计的绝佳示例,因此,如果有空的话,请看一下API参考。)

6. 演化

传统的Web应用程序一直在更新:设计和添加新功能,改进和简化流行功能,弃用和删除不使用的功能。用户习惯于在不断变化的环境中生活和操作,有时环境会发生巨大变化。

大多数时候,产品在吸引用户采用新功能方面做得非常好:新闻通讯,应用内参观和良好的设计习惯可确保UX不会因最新的全面更新而中断。

另一方面,对于API来说,似乎只有两个可能的选择:要么从不更改接口以免破坏实现,要么不经通知就更改它,从而破坏了大多数客户的工作。发生这种情况是因为API团队通常不会与用户群断开连接,因为它们不会直接与用户互动。

但是,第三个选择是完全可能的:有了正确的基础架构和工具,您就可以拥有以对其用户可管理的方式进行更改的API。您可以使用度量标准来做出有关您公开的界面的明智决定:端点使用频率是多少?最近6个月内,有哪些用户称其为特定的API端点?确保您始终可以回答此类问题,因为它们将使您无需担心用户一天的噩梦就能开发自己的API。

如果一个对象有多个方法加了 synchronized,那么该对象有几把锁?

答案是一把锁 🔐

代码示例:

1
2
3
4
5
6
7
8
9
10
11
public class Test {

public synchronized void method1(){
// do something
}

public synchronized void method2(){
// do something
}

}

对象锁是在一个类的对象上加的的锁,只有一把,不管有几个方法进行了同步。

这些同步方法都共有一把锁,只要一个线程获得了这个对象锁,其他的线程就不能访问该对象的任何一个同步方法。

对象锁:

synchronized 修饰实体里的非静态变量,锁的是对象

synchronized 修饰代码块,锁的是对象

synchronized 修饰非静态方法,锁的是对象

使用对象锁的情况,只有使用同一对象的线程才会受锁的影响,多个对象调用同一方法也不会受影响。

类锁:

synchronized 修饰类中的静态变量

synchronized 修饰静态方法

synchronized 修饰类.class

类锁是所有线程共享的锁,所以同一时刻,只能有一个线程使用加了锁的方法或方法体,不管是不是同一个实例。

参考文章:

https://blog.csdn.net/qa275267067/article/details/79804713

https://www.cnblogs.com/fengzheng/p/12066239.html

多个单列索引和联合索引的区别详解

原文地址:https://blog.csdn.net/abysscarry/article/details/80792876

作者:深寒丶

对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用仅对后面的任意列执行搜索时,复合索引则没有用处。

or索引失效:

所谓的索引失效指的是:假如 or 连接的俩个查询条件字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描。我们从 or 的基本含义出发应该能理解并认可这种说法,没啥问题。

背景:

为了提高数据库效率,建索引是家常便饭;那么当查询条件为 2 个及以上时,我们是创建多个单列索引还是创建一个联合索引好呢?他们之间的区别是什么?哪个效率高呢?我在这里详细测试分析下。

一、联合索引测试

注:Mysql 版本为 5.7.20

创建测试表(表记录数为 63188):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE TABLE `t_mobilesms_11` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userId` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户id,创建任务时的userid',
`mobile` varchar(24) NOT NULL DEFAULT '' COMMENT '手机号码',
`billMonth` varchar(32) DEFAULT NULL COMMENT '账单月',
`time` varchar(32) DEFAULT NULL COMMENT '收/发短信时间',
`peerNumber` varchar(64) NOT NULL COMMENT '对方号码',
`location` varchar(64) DEFAULT NULL COMMENT '通信地(自己的)',
`sendType` varchar(16) DEFAULT NULL COMMENT 'SEND-发送; RECEIVE-收取',
`msgType` varchar(8) DEFAULT NULL COMMENT 'SMS-短信; MSS-彩信',
`serviceName` varchar(256) DEFAULT NULL COMMENT '业务名称. e.g. 点对点(网内)',
`fee` int(11) DEFAULT NULL COMMENT '通信费(单位分)',
`createTime` datetime DEFAULT NULL COMMENT '创建时间',
`lastModifyTime` datetime DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`),
KEY `联合索引` (`userId`,`mobile`,`billMonth`)
) ENGINE=InnoDB AUTO_INCREMENT=71185 DEFAULT CHARSET=utf8 COMMENT='手机短信详情'

我们为userId, mobile, billMonth三个字段添加上联合索引!

我们选择 explain 查看执行计划来观察索引利用情况:

1.查询条件为 userid

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222'

可以通过key看到,联合索引有效

2.查询条件为 mobile

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972'

可以看到联合索引无效

3.查询条件为 billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE billMonth='2018-04'

联合索引无效

4.查询条件为 userid and mobile

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972'

联合索引有效

5.查询条件为 mobile and userid

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE  mobile='13281899972' AND userid='2222'

在 4 的基础上调换了查询条件的顺序,发现联合索引依旧有效

6.查询条件为 userid or mobile

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' OR mobile='13281899972'

and 换成 or,发现联合所索引无效

7.查询条件为 userid and billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND billMonth='2018-04'

这两个条件分别位于联合索引位置的第一和第三,测试联合索引依旧有效

8.查询条件为 mobile and billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'

这两个条件分别位于联合索引位置的第二和第三,发现联合索引无效

9.查询条件为 userid and mobile and billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE  userid='2222' AND mobile='13281899972' AND billMonth='2018-04'

所有条件一起查询,联合索引有效!(当然,这才是最正统的用法啊!)

二、单列索引测试

创建三个单列索引:

1.查询条件为 userid and mobile and billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE  userid='2222' AND mobile='13281899972' AND billMonth='2018-04'

我们发现三个单列索引只有 userid 有效(位置为查询条件第一个),其他两个都没有用上。

那么为什么没有用上呢?按照我们的理解,三个字段都加索引了,无论怎么排列组合查询,应该都能利用到这三个索引才对!

其实这里其实涉及到了 mysql 优化器的优化策略!当多条件联合查询时,优化器会评估用哪个条件的索引效率最高!它会选择最佳的索引去使用,也就是说,此处userid 、mobile 、billMonth这三个索引列都能用,只不过优化器判断只需要使用userid这一个索引就能完成本次查询,故最终 explain 展示的 key 为 userid。

当然,如果优化器判断本次查询非要全使用三个索引才能效率最高,那么 explain 的 key 就会是userid 、mobile 、billMonth,都会生效!

2.查询条件为 mobile and billMonth

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'

我们发现此处两个查询条件只有 mobile 生效(位置也为查询条件第一个)

3.查询条件为 userid or mobile

1
EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE  userid='2222' OR mobile='13281899972'

这次把 and 换成 or,发现两个查询条件都用上索引了!

我们在网上可能常常看到有人说 or 会导致索引失效,其实这并不准确。而且我们首先需要判断用的是哪个数据库哪个版本,什么引擎?

比如我用的是 mysql5.7 版本,innodb 引擎,在这个环境下我们再去讨论索引的具体问题。

关于 or 查询的真相是:

所谓的索引失效指的是:假如 or 连接的俩个查询条件字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描。我们从 or 的基本含义出发应该能理解并认可这种说法,没啥问题。

此刻需要注意type类型为index_merge

我查资料说 mysql 5.0 版本之前 使用 or只会用到一个索引(即使如上我给 userid 和 mobile 都建立的单列索引),但自从 5.0 版本开始引入了index_merge 索引合并优化!也就是说,我们现在可以利用上多个索引去优化 or 查询了。

index_merge 作用:

1、索引合并是把几个索引的范围扫描合并成一个索引。

2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。

3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。

index_merge 应用场景:

1.对 OR 语句求并集,如查询SELECT * FROM TB1 WHERE c1="xxx" OR c2=""xxx"时,如果 c1 和 c2 列上分别有索引,可以按照 c1 和 c2 条件进行查询,再将查询结果合并(union)操作,得到最终结果

2.对 AND 语句求交集,如查询SELECT * FROM TB1 WHERE c1="xxx" AND c2=""xxx"时,如果 c1 和 c2 列上分别有索引,可以按照 c1 和 c2 条件进行查询,再将查询结果取交集(intersect)操作,得到最终结果

3.对 AND 和 OR 组合语句求结果

三、结论

通俗理解:

利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处

所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用仅对后面的任意列执行搜索时,复合索引则没有用处。

重点:

多个单列索引多条件查询时优化器会选择最优索引策略可能只用一个索引,也可能将多个索引全用上! 但多个单列索引底层会建立多个 B+索引树,比较占用空间,也会浪费一定搜索效率,故如果只有多条件联合查询时最好建联合索引!

最左前缀原则:

顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上,
注:如果第一个字段是范围查询需要单独建一个索引
注:在创建联合索引时,要根据业务需求,where 子句中使用最频繁的一列放在最左边。这样的话扩展性较好,比如 userid 经常需要作为查询条件,而 mobile 不常常用,则需要把 userid 放在联合索引的第一位置,即最左边

同时存在联合索引和单列索引(字段有重复的),这个时候查询 mysql 会怎么用索引呢?

这个涉及到 mysql 本身的查询优化器策略了,当一个表有多条索引可走时, Mysql 根据查询语句的成本来选择走哪条索引;

有人说 where 查询是按照从左到右的顺序,所以筛选力度大的条件尽量放前面。网上百度过,很多都是这种说法,但是据我研究,mysql 执行优化器会对其进行优化当不考虑索引时,where 条件顺序对效率没有影响真正有影响的是是否用到了索引

联合索引本质:

当创建**(a,b,c)联合索引时,相当于创建了(a)单列索引(a,b)联合索引以及(a,b,c)联合索引**
想要索引生效的话,只能使用 a 和 a,b 和 a,b,c 三种组合;当然,我们上面测试过,a,c 组合也可以,但实际上只用到了 a 的索引,c 并没有用到!
注:这个可以结合上边的 通俗理解 来思考!

其他知识点:

1、需要加索引的字段,要在 where 条件中

2、数据量少的字段不需要加索引;因为建索引有一定开销,如果数据量小则没必要建索引(速度反而慢)

3、避免在 where 子句中使用or来连接条件,因为如果俩个字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描

4、联合索引比对每个列分别建索引更有优势,因为索引建立得越多就越占磁盘空间,在更新数据的时候速度会更慢。另外建立多列索引时,顺序也是需要注意的,应该将严格的索引放在前面,这样筛选的力度会更大,效率更高

最后的说明:

网上关于索引优化等文章太多了,针对各个数据库各个版本各种引擎都可能存在不一样的说法

我们的 SQL 引擎自带的优化也越来越强大,说不定你的某个 SQL 优化认知,其 SQL 引擎在某次升级中早就自优化了。

所以要么跟进官方文档,要么关注数据库大牛的最新文章,要么在现有数据库环境下自己去亲手测试!

数据库领域的水很深。。大家加油。。共勉 ~

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

原文地址:https://36kr.com/p/5273796

作者:林鲁比@36氪Pro

竞争、分化、抢人…2020年八个人才资本趋势。

近日,Boss直聘在北京举办了年度合作伙伴大会“ECHO2020”,在活动上发布了《2020人力资本趋势报告》,该报告由Boss直聘职业科学实验室及 Boss直聘研究院制作出品。

报告数据来源于Boss直聘平台以及《2020求职需求趋势调查》3060份调研问卷,其问卷样本包括23%核心高管、32%部门负责人以及45%的人力资源专员,覆盖互联网/IT/软件、电子通信、教育、金融、房地产、文娱等16个以及行业。

该报告主题为“突变时代”,突变的概念最早由法国数学家勒内 ▪ 托姆提出,他将系统内部状态的整体性“突跃”称为“突变(Mutation)”,主要用于形容过程连续但是结果不连续的状态。随着当前环境不确定性和市场竞争的加剧,企业为适应环境,其组织架构、人员调度也常常出现“突变”的状态:业务重组、撤销、工作流程设计等等频繁出现。突变理论认为,变革无法被管理,只能被影响,认识到突变时代的到来仅仅是第一步,更重要的是主动应对突变的环境。

在“就业市场—组织发展—个人发展”的研究视角下,Boss直聘总结出来了2020年的八大人才资本趋势,以下是报告的一些要点:

趋势一:竞争分化加剧,能力比拼的勇敢者游戏

报告认为,2019年就业市场的关键词是竞争与分化。

2019年企业招聘需求同比增加21%,平均招聘薪资为8082元,同比回落0.4%。求职市场竞争激烈主要体现在高校应届生数量增加;雇主对求职者的要求普遍提高;35岁以上主动求职者规模扩大;求职者薪资议价空间缩窄等方面。

在《2020求职需求趋势调查》中,67.8%的求职者认为今年在求职过程中“明显感到竞争更加激烈”,24.9%认为“有一定感受,但影响不大”,仅有7.3%认为竞争压力没有变化。

与此同时,企业的人才竞争也在加剧,63.3%的企业认为通过外部招聘补充合适人才的难度“明显变高”,32.9%的企业认为“有一定感受,但影响不大”,仅有3.8%的企业表示“没有类似感受”。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

数据显示,2019年招聘薪资分布曲线如上,正偏态分布十分显著,众数为5000元,中位数为6043元,平均薪资为8082元,即5000元是最常出现的月薪水平,有一半的招聘薪资数据低于6043元。

2019年薪资分布曲线向两端小幅移动,一方面是企业控制人力成本的表现,另一方面还说明求职者内部竞争两极化的加剧。

趋势二:新兴职业崛起,人才成长追逐的追逐战

随着各种新兴行业崛起,人工智能、大数据岗位、电竞玩家、无人机飞手、带货主播等岗位从无到有,从有到“热”。新职业发展过程中,学校教育已经落后于行业发展速度,企业人才培训的重要性也愈加凸显。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

与大数据相关的岗位人才增速开始减缓,对中高端人才能力要求提升。

人工智能领域人才处于高速增长红利期。

网络直播、电竞领域人才处于爆发式增长,高度低龄化的阶段。

云计算、5G领域核心人才尚未迎来增长拐点。

趋势三:区域化抢人大战升级

报告指出,当一个城市推出“抢人政策”,其所处区域内其他城市也会竞相推出类似政策,“城市抢人”明显向“区域化抢人”转变。

2019年一线城市(北上广深)人才持续留至新一线城市和省会城市。报告数据显示,截至2019年11月,一线城市职场人净流出率为0.58%,较2018年同期增加0.05%个百分点。杭州、东莞、武汉、长沙、苏州成为2019年求职者离开一线城市后的首选5大城市。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

趋势四:定制工作旅程,创造全息式员工体验

为了吸引人才,许多企业在招聘阶段采用“薪资-文化-愿景”相结合的手段,但在人才入职后仍采用老旧的员工管理系统,先热后冷的处理方式潜藏人才流失风险。

报告认为,有必要从时间和空间两个维度继续对员工体验流程进行扩充,传统的流程式工作体验正变为旅程式工作体验,由此报告提出了一种新的员工体验图,即全息式员工体验图。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

趋势五:重构信息网络,识别“真实组织架构”

报告认为,真实的组织架构由“解决一个问题应该去哪里、需要几个步骤找到正确的对接人,他们是否在组织中处于合适位置”决定,这是一张充满变化的复杂弹性网络。

组织网络分析(ONA,Organizational Network Analysis)是一项被证实有效的组织发展工具,其核心目标是刻画组织内的信息流动现状,进而判断信息“能够”如何流通和“应该”如何流通,并做出相应优化动作。

趋势六:精练技能图谱,为职场竞争力定价

报告发现,技能在职场中发挥的作用日益明显,更多企业不再单纯依赖求职者的自立,更易核心技能为导向筛选求职者。人工智能、算法类仍然是2019年最吃香的技能。

除了技术技能,软技能也受到企业关注,并且在某些行业和特定职位中,已经出现软技能等同于硬技能的迹象,企业对求职者创新性、创造力的要求越来越高。其中,时间管理能力、系统性思考能力、解决问题能力这三项软技能的竞争力排名靠前。

另外,在Boss直聘《2020企业人才需求趋势调查问卷》中,雇主最希望员工和候选人提升的素质能力还包括自主学习、人际沟通与协调、抗压与情绪管理能力。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

趋势七:建设职场公平游戏

近年来随着女性进入职场的比例逐渐升高,职场公平凸显一个窘境,即“大多数女性会停留在无法充分发挥其能力的岗位上”,这种现象被归纳为“宝拉原理(Paula Principle)”,相关现象被描绘为“玻璃天花板”效应和“粘地板”效应。

报告通过模型计算,探究在排除偏见和刻板印象之后,女性在“公平游戏”中的表现,男女性优于表现稳定程度带来职业发展差异,在一定程度上说明运气正在职业发展中的巨大作用。男性优于运气获得的收益,最终都将转化为组织的成本,使整体产出下降。能够连续获得晋升的女性往往比男性有更高的工作能力,玻璃天花板使得人力资本较高的女性无法充分施展,实际上降低了组织的整体绩效。

趋势八:超越培训式学习,培养终身学习能力

格哈德 ▪ 费舍在其研究中指出,学习已经跨越了时间和空间的限制而进入全方位覆盖的阶段,即“终身学习(lifelong learning)”。报告指出,培训和终身学习、学校式学习和工作式学习在不同维度有差别。

在《2020求职需求趋势调查》中,比起求职者,雇主对学习能力的需求明显更高,这反映出工作化场景和在实践中交互对于终身学习能力培养的必要性。

Boss直聘发布《2020人才资本趋势报告》,突变时代迎来八大趋势

报告还发现,掌握终身学习能力可以降低转岗难度,也可以使求职者在相同类型的岗位上更容易完成晋升和提升,而且,对学习能力的需求还带动了培训行业的兴起。

《程序员修炼之道》书评

原文地址:https://book.douban.com/subject/5387402/

1 我的源码让猫给吃了

不要寻找借口,从自身找原因

2 软件的熵

一句话:不以善小而不为,勿以恶小而为之.

从初期就要做好规范,不要因为是poc这样的前提而放松对代码的规范,现在的项目就
有这种问题,初期的时候有人认为(自己也有这种想法)等到以后正式开发的时候再规范
,而往往还未到正式开发,到处出现不规范的东西.加上拷贝粘贴的大法,亡羊补牢都晚
了.这就是所谓破窗户理论.

3 石头汤与煮青蛙

两个方面,一还是’软件的熵’当中的含义,喜欢书里面的这段话:’大多数的项目的拖
延都是一天一天发生的,系统一个特性一个特性的偏离其规范.一个又一个的补丁被打
到某段代码上,直到最初的代码一点没有留下’. 二是团队的协同合作,这样石头汤也很
鲜美.

4足够好的软件

就是俗话说的一鸟在手胜于二鸟在林.
首先得确保软件可用性,至于亮点,特色,在可用以后才需要考虑.而且还得明确用户需
求(虽然这点始终被强调).大家都知道系统不可能做的完美,但是自己着手开发的时候
总是朝着尽可能完美的方向发展,欺骗自己说,这个功能多么伟大,一定要加上去,那个
功能多么惊天动地,最后反而成为四不像,使项目延期.
在第一次企图做那个todo list的时候,想着把calendar和task两项功能完整的结合,
同时还想着把contact功能也加入,甚至还有ms porject的管理功能,但是一切都太多,
以致于设计了少数几个界面以后就陷入了无止境的功能权衡中,因为太多东西又想完美
.所以第一次最终结果是除了最后那个简陋的复杂的界面,什么东西都没有,当然如今代
码也已经不知道是不是被自己删除,能够留在自己硬盘上并且使用的还是那个简简单单
的GeeTask,功能不多,但是的确对我来说,足够好了,如果还有新的功能,添加就是了,不
用一次就做一个大而全的玩意出来.
也想起在上一个公司参与的第一个项目,房地产的预警系统,先前同事通过研究,不知
道从哪里搞到一些其他人做的预警系统,动用高深的所谓经济学景气循环算法来计算,
艰难的实现这些公式.当然我们自己也不知道这个是不是准.后来我负责去给客户实施,
在客户处,得知了惊人的消息:客户需要的足够好的软件其实就是一个新闻发布功能的
东西,因为他们也不懂,是领导的要求—领导当然也是被上层领导要求.这个例子虽然
特殊,但是也说明了一定要及早知道客户心中的足够好的软件是什么.

5 你的知识资产

关于学习的一个章节,提到了不少如何学习,把学习知识作为投资一样看待,分析的也
很在理.自认为在这方面还是赶上了书中的要求,不然也不会看到这本书了^_^,学习是
一个过程,不会有立杆见影的效果,当然我们不是政客,不需要立马可见的政绩,那么种
种树又何妨呢?学习也要有实践,把学到的知识找机会就应用起来,起码,自己没用到,也
可以看看别人怎么用嘛.学的多了自然有了自己的判断,前两天不小心点开了jdk源码当
中关于Arrays.sort方法的实现.看到内部的合并排序法却不如《算法导论》中描述的
那么简洁,那么具有可读性,这时候,有了判断了,就不至于傻乎乎的研究它的写法,当然
,jdk里面的mergesort又有一些额外的处理(小数组优化),这个又是可以学习的地方.对
了,这一小节里面还有一段关于如何获得答案的方法,和国内论坛风靡一时的《提问的
智慧》一文有多处相似之处,不知道作者是否参考了本书.

6 交流

这个不用说就知道重要了.离开上一家公司最后一个项目就是最好的例子,一开始其
他同事从客户处带回来老系统的截图以及一些需求的说明,然后我们就要按照这些支离
破碎的东西进行开发.我们不是先知,不是某些领导人,可以自由的发挥,于是绞尽脑汁,
开始努力向可以吻合的方向发展,这种日子很不好受,直到我可以与客户联系上以后,直
接的面对面的确认客户的需求(又是需求) 才让项目的进展在几天里面比前面一个月都
要好的多.

7 重复的危害

有时候是copy paste大法带来的后果,有时候是为了省事,总之,一份功能相同的代码在多处出现,更要命的是,需要修改这部分代码!这个可以毫不客气的说就是灾难,所以在设计,在编码初期就要有良好的规划,尽可能避免重复。实际工作中,发行有时候,尽管想要刻意避免,但是还是会出现。其中一个重要原因在于程序员的偷懒,还有是在于模块的可访问性。尤其是两个模块没有任何公用模块的时候,如何避免重复,或者说人工重复才是问题的关键,即使是build脚本去让两个模块出现相同的东西,也比人为维护两个东西都要好上千万倍。

8 正交性

模块耦合,代码耦合,分层分模块,善用设计模式。正交的目标只有一个,让系统富有弹性,可以随需应变。

9 可撤销性

还是系统的可变性,是否可以快速应付其中一些改变而快速改变。通常我们用面向接口的方式来做到这些。在前人的基础上,我们有corba ,com,ejb,webservice,odbc,jdbc等等让我们快速应变的基石,但是总有一些依赖我们自己的东西,接口,接口!

10 曳光弹

很炫的名字,可惜就是在讲poc,Prove of Concept ,的确很有用。

11 原型与便笺
原型,没别的,常用的东西。

12 领域语言

不同语言有不同的优势,关键在于扬长避短,合理运用,有时候组合起来事半功倍。

13 估算

开始前做好计划,过程中最终计划,磨刀不误砍柴工。

14 纯文本的威力

很多时候纯文本的简单让事情更容易。

15 Shell游戏

程序员必须掌握命令行,即使在windows下面。

16 强力编辑

知道vi好,但是只会那么几个简单的命令,而且,通常我总是在windows下面工作,所以通常用crack的UltraEdit。不少实用的功能,加速编辑。倒是IDE的快捷键记住了不少,在实际工作中,发挥了很大的作用。
书上提到仍有不少人使用windows notepad写代码,我虽然不至于此,但倒是习惯使用它来写文章,记录东西,然而就在刚才,发现手工输入的东西都会出现几个黑色的黑框,可见一定要选择足够好的编辑器才行,何况,windows notepad只能撤销一次,而且你也不会知道撤销的到底是你那次的输入。

17 源码控制

凡是工作过的程序员,没有不用源码控制工具的吧? 只是选择有所不同。

18 调试

读书的时候学习编程,觉得和其他人最不一样的地方在于两点,一是自己思考程序的流程,写下代码之前,知道代码将要(预期)执行的顺序逻辑,二是会调试代码,出现错误时不像一般人完全不知道该如何是好,而是去调试来寻找出错的原因。我相信,现在还是有不少工作了的程序员,不习惯去调试,他们期待的是自己的代码都是一次编写就能正确无误的执行,如果不行,那么别人大概可以帮忙解决。

一直以来,一直觉得,一个程序员的经验丰富情况很大程度依赖于他遇到的bug并解决的数量,所以一个人代码写的越多,解决的问题越多,那么他下次遇到问题时就越容易很快的定位。所以,有时候遇到问题并且成功的选择另外一个方案绕过去以后,不妨回头再看看原来到底为什么不行,毕竟下次也许你又要遇到,而且,更重要的是,可能到时候不能选择其他的方案。

19 文本操纵

这一节没理解它真正的含义,表面看来是讲可以使用程序来读取操作文本的信息,来加快工作效率,但是到底指什么呢?不明白。不过倒是在工作上,多次嫌手工执行一些转换数据库工作麻烦,而写一些简短的工具来做批处理,效果也很不错。

20 代码生成器

经常用,很好用。

21 按合约设计

以前也看过类似的文章,当时还把它贴到公司的wiki上面,并且自从那以后一直坚持契约的方式编程。长久一来,我一直认为这是行之有效的方式,每个人把注意力放到自己的代码中,对他人的代码只作检查,不做包容,如果,对方的屁股没擦干净,一脚踹出去比请进来帮他擦更让人能够觉得舒畅,而且,也能防止有些家伙习惯性的先把屁股伸进来。

至于断言,以前学习VC6的时候因为其对程序的终止而不那么喜欢,而并非每次都写JUnit 也让自己并非常用。

22 死程序不说谎

代码总是忠实的执行程序员的指令。一切程序员的错误最终将反映到代码上面来,在代码中随时做好踹别人屁股,甚至踹自己屁股的准备,因为崩溃比继续错误的运行更有好处。

23 断言式编程

就是断言,同21节中的内容。

24 何时使用异常

因为在用java所以一直在和异常打交道,系统的,别人写的或者是自己写的。异常的处理可以说是所有java应用中最普遍的东西。配合上面3节,合理使用,让异常发挥最大的效用。

25 怎样配平资源

记住并切实的执行一个原则:打开的资源一定要关闭,这个资源可以是文件,内存,io或者其他。虽然有些语言比如java有GC来管理内存,但是却管理不了文件,c的野指针问题,也都是因为只顾申请却不记得释放导致。还是前面的老话,屁股要自己擦干净,擦不干净当然会把裤子弄脏,脏了裤子是小,臭味熏了别人是大。

26 解耦与得墨忒耳法则

没明白得墨忒耳法则的具体确切内容,不过减少耦合总是不错的。

27 元程序设计

很多东西都应该以配置文件的形式来处理,这样的好处显而易见:修改这部分内容无需重新编译代码。而今,我又有一些新的体会: 配置可能会带来配置满天飞的灾难,所以一定要清晰易懂的配置。

28 时间耦合

工作流的东西,到现在还没有去瞅过,管他呢,用的到时再说吧。

29 它只是视图

mvc 常用的不行的东西,发布/订阅,这个也是在设计、编码过程中自然而然想要使用的玩意。

30 黑板

是指多系统共用数据吗?看着有点像,不确定。

31 靠巧合编程

编写代码的方式是知道要做什么,然后写代码。所以要清楚的知道自己的代码每一步都做了些什么。对于很多程序来说,通常情况下,它是正确的,而某些情况下它却不正常了,那么这就可以归属于靠巧合编程。程序的错误,很多时候在于对边界条件的判断。

32 算法速率

就目前来说,项目已经很少需要精确到一个具体算法的速度,但是在比较广义的范围内,减少不必要的计算,提高整体运算速度,还是会是系统看起来更好。本节提到的算法复杂度,在很多书中都被提及,但是我从一开始就忽略了这部分的学习,所以,通常情况下,总是不知道一个算法的具体复杂的(总是忘记某些重要的结论,比如递归算法的复杂度计算公式),所以这个一定要补上来。

33 重构

没什么好说的。

34 易于测试的代码

测试,保障代码质量,没什么好说的。

35 邪恶的向导

为了节约时间,出现了各种向导工具,同时也让不明就里的人失去了了解细节的机会,因而,懒惰的人更不会去理会向导做了什么事情,这就是邪恶的原因所在。

36 需求之坑

终于到了需求的部分,可是有没什么好说的了。

37 解开不可能解开的迷题

有时候问题的解决需要跳出常规的思维。或者简单一点,用另外一种方法,而不是钻牛角尖。

38 等你准备好

不打无准备的仗。没什么好说的。

39 规范陷阱

不要等万事具备才开始,因为不可能万事具备,用户总是在变。

40 圆圈与箭头

工具是拿来帮助加快开发,而不是束缚开发的。各种各样眼花缭乱的UML,其实只是为了能够清晰描述设计者的思想。当我还是高中生的时候,老师在课堂上面讲述着流程图这种工具,当时甚至5、6年以后我都没听说过uml,但是觉得流程图就是那么的实用。如今,已经很少见到有谁在使用流程图来描述。也许和设计的关注点不同有关,但是当自己在使用uml进行设计时,却又十分的想使用流程图,可惜,像rose之类的工具都没有,也不知道uml是否定义。viso倒貌似有,可是还没用过。前不久找了一个开源的digramdesinger的工具,在这方面倒做的不错。

41 注重实效的团队

项目开发就脱不开团队,个人的项目除了兴趣爱好,还没听说过。团队重要性不言而喻,以往的经历告诉我一个合理的团队让人觉得有归属感,反之,就容易萌生去意。一起喝着可乐,听着破喇叭放出的音乐,并且加着班的团队在多年以后的记忆里面显得那么的美。

42 无处不在的自动化

程序的目的之一就是让原本繁琐复杂的重复劳动自动化的处理,而软件开发过程中也一样需要自动化。我一直坚信别人说过的一句话:凡是有人参与的过程,肯定会产生错误。所以,我也一直坚持能让机器去做的事情就交给机器,以减少人的参与,减少错误的发生几率。在过去,我尝试了多次为某些任务编写简单的程序来自动化处理,虽然,我的计划上,没有写一个程序这样的描述,但是,写程序自动处理更好,更有效,最重要的是,还能再次重复预设的动作。此外其他的自动化工具也是很值得推荐,比如自动化测试,代码生成器。

43 无情的测试

测试是为了保障代码的质量。所以越是仔细,全面的测试,越是有助于系统的健壮,不负责任的程序员或者测试,总是拿着可以正常运行的数据来进行着测试。有条件还是需要专职的测试,合格的测试,而不是那种连代码都看不懂的刚毕业的小姑娘。

44 全都是写

文档和注释。自认为注释方面还过得去,但是有些情况下还是会忽略注释而后期弥补,这一点需要改正。 至于文档倒是需要好好努力的,这样能显的更“专业”,能更好的记录代码的情况。

45 极大的期望

达到客户的期望,才是软件真正的成功。这一点,其实又涉及到“万恶的”需求。刚刚经历了一段做完的曳光弹被客户枪毙的事情。其实这一切,如果能从一开始就得到客户的期望,就不会如此的糟糕。而事实却是客户的期望,客户的需求却并非可以得到。虽说这不是好的软件工程的典型,但是至少,我们现在知道了什么是客户期望的。

46 傲慢与偏激

很cool的名字,不是吗?其实只是指了一个小事情,在你的代码上面留下你的足迹。这一点,在第一个公司的时候就已经养成了习惯,并且保留到现在。虽然现在没有诸如此类的要求,但是我还会继续这么做下去,因为对于自己,对于队友,都是很重要的好习惯,当别人发现有问题时,可以马上过来问我:嘿,为什么会有这个问题。他可以节约自己的时间,我也可以有机会再一次增加自己的经验(参见我之前的感受)。而且留下自己的痕迹,也留下一份责任心,不负责任的人,马上就能被发现。

毁了你职业生涯的三个错误认知!

原文地址:https://mp.weixin.qq.com/s/4J_4Mfwd8PYd8VyBB0LXbA

小结:

三个错误认知:

  1. 进行大量重复练习?

    反复练习是效率最低的一种方式。这种学习方法是在助长人的惰性。单纯地重复练习意味着我们在机械地、快速地重复一些东西,想把它们烙在自己的记忆里

    读书-思考-行动-反思

  2. 努力努力再努力?

    底层逻辑是我们在思考问题的时候,最先的核心切入点,从这个点开始思考,从而作出之后的决定。

    当围绕着底层逻辑思考时,做出的决定才是和初心一致,最贴合内心的,也是真实的人性反馈。

  3. 一定要用最新,最流行的工具?

    在尝试了使用工具便捷的甜头后,于是,我们容易掉进一个误区:追求使用最新,最流行的工具。

    技术人,不要老是埋头敲代码,要有点产品思维,要注重思想上的提升。语言只是一种工具,一种实现的手段,不要只做工具的奴隶,而要做思想上的巨人。

    一个只会熟练使用编程语言的程序员,如果只是一味地追求编程技术上的精进,而不注重编程思维的提升,那么也很难以获得新的突破。

    技法固然重要,但凌驾于技法之上的,却是一个人的思想高度

  4. 最后

    我们之所以努力,是因为努力本身能拓展我们的能力。你所做的事情决定了你会成为什么样的人,决定了你有能力做什么。你做的事情越多,你能做的事情也就越多。

个人思考:

重复练习是在助长人的惰性,习得-思考-行动-反思

找到问题的底层逻辑

要注重编程思维的提升

众所周知,在技术迅速转变、业务要求不断变化的 IT 行业,重塑职业道路似乎成为一个关乎生存的问题。

那么,程序员想要不被淘汰,避免自己在职场上过早地走入死胡同,最稳妥的办法–接受新技术,保持终身学习。

问题是,如何学?该避免哪些认知误区?

1. 进行大量重复练习?

在开始之前,我先跟大家分享一个故事:

上高中的第一天,班里来了一位学习非常刻苦勤奋的同学。这位同学勤奋到什么程度呢?书桌上的资料书堆起来后,可以完全把她淹没。课余时间,我们一般都会稍作休息,聊聊天,活动活动之类。

但她是那种一刻钟都不肯浪费的人。当我们在玩耍时,她在读书学习;当我们在学习时,她也在学习;当我们午休时,她还在争分夺秒学习。晚上宿舍关灯休息时,她就会走到楼道里,借着昏暗的灯光继续学。

像她这种勤奋的孩子,我们都以为她成绩很厉害。结果考试成绩出来,吓了我们一跳:全班倒数第五名。

后来我们发现,她所谓的勤奋,其实不过就是在不断重复背题,实践题海战术。好读书,但不求甚解。是典型的“死记硬背”类型。碰巧背对了题,成绩就会上升。一旦题目“变”了身,成绩就急剧下降。

我们一直以来接受的教育就是,倘若想要学好某门技能,就应把注意力完全放在这上面,然后通过不断重复的练习、练习、练习,直到掌握为止。

而我们大多数人,都对这个方法深信不疑。因为曾经在考试期间,通过在集中练习后,在短期内效果显著,尝过甜头。

像这种不断重复的练习,往往见效快,但时间一长,就暴露出其弊端。

在《认知天性》一书中,作者认为,反复练习是效率最低的一种方式。这种学习方法是在助长人的惰性。单纯地重复练习意味着我们在机械地、快速地重复一些东西,想把它们烙在自己的记忆里。

最熟悉的例子就是考前的”填鸭”,这种错误的方式让人觉得自己已经很熟练了,已经掌握了知识,但实际上这种方法不仅做不到真正的精通,也不会产生持久的记忆。

那么正确的方法是什么呢?书中提出了一些解决方案,而我感受最深的莫过于间隔练习。

我曾经有过这样的经历:

记得有一次,项目中要引入新技术,需要我们自己折腾学习。当时在学习的时候,遇到了一个技术性问题,而周遭又没有人可以指导,只能自己上网搜索。

当时只有一个心里念头:今晚不把问题解决,誓不罢休!

于是,加班加点,反复尝试,不断折腾。可是无论怎么折腾,结果还是没有任何进展,反而效果越来越糟糕。

夜已深。无奈之下,只好先行放弃。可待睡一觉后,第二天再尝试时,发现好像突然开窍,完成得比前一天更好。

这里,涉及到一个“间隔练习”的问题。间隔练习,在这里,我把它称之为“爱迪生工作法”,这个工作方式,类似于我们平时所说的“劳逸结合”方式。

据说爱迪生在工作一段时间后,就会躺在躺椅上小憩。每次他手里都会抓住一个铁球,如果不小心进入了深度睡眠,手里的铁球就会掉到地上把自己弄醒。这样,他就可以享受那种半梦半醒的状态,也是最有创造力的一段时间。

这也是我比较喜欢的一种工作方式。每学习或者工作一段时间后,休息一小段时间放松,这样让身心保持在一个舒适的状态,更容易让大脑建立新的连接,效率比持续工作/学习要好很多。这也是间隔练习带来的好处。

关于该如何有效学习,在《认知心理学》里,提出了PQ4R法,即预习-提问-阅读-反思-复述-复习

简单可以归结为,“读书-思考-行动-反思”循环模式。通过这个循环进行读书,才能把一本书逐渐读透。这个模式应用在学习,工作流程上也同样适用。

学习是反人性的事情,当你感觉难,那就是正确的状态!在安德斯·艾利克森的《刻意练习》这本书的理论基础是“刻意练习自己不擅长的部分”。这个过程会让大脑处于一种非常不舒服的状态,会非常艰辛,若想有所成,前路必然艰辛。

关键是,要在正确的方向上使力。认知错了,一切努力都是徒劳。

2. 努力努力再努力?

有时候会发现,明明自己已经很努力,却依然还是没有找到解决问题的方法,别人稍稍发力,就能迅速地找到突破口。这里涉及到另一个关键点–底层逻辑。

滴滴打车的创始人程维说过,“遇到任何难以解决的问题,就会去想,最关键的底层逻辑是什么?”

那么,什么是底层逻辑?这里,可以理解为我们在思考问题的时候,最先的核心切入点,从这个点开始思考,从而作出之后的决定。

当围绕着底层逻辑思考时,做出的决定才是和初心一致,最贴合内心的,也是真实的人性反馈。

这个怎么说呢?

在《颠覆认知》一书中,作者曾列举过一个例子:

你教小朋友骑自行车,如果跟他说一大堆平衡理论,动力理论,他还是学不会。你只要告诉他底层逻辑–向前奔跑的自行车不会倒下,那么他自己捣鼓一下,很快就能学会。

它的底层逻辑是什么,关键就是要看它能在根本上解决什么问题。作为新手,这个需要花时间去折腾,通过对事物的深入理解,熟悉后才能找到。

而在商业模式里,一个公司的底层逻辑,往往与其定位密切相关。

例如,苹果公司的底层逻辑是“极致的人机交互体验”,所以苹果的产品设计都是“体验优先于性能”;

腾讯的底层逻辑是“用户体验”,所以腾讯员工的动作靠两个东西来约束:一个是KPI,另一个就是“用户体验”这个核心价值认知,而且用户体验大于KPI;

有了底层逻辑,公司在遇到难以解决的问题时,也就有了破题的切入点,这也是公司成功的一个关键。

同理,可以引申到学习与工作中去。

类比到学习。当学习java编程语言时,学过c语言的人可能更容易上手,因为学习语言的底层逻辑相同;当物理上讲到加速度时,有玩过过山车经验的人可能更容易理解。

这个学习的过程,就像滚雪球一样,越滚越大。随着经验的丰富,看待世界更为成熟,面对新知识时也就更容易触类旁通,举一反三和迁移。

这些禀赋,在切换到新领域之后,都可以顺利移植,构成我们常说的底层逻辑。

这种底层逻辑,与法纳姆街博客上解释说的心智模型有着异曲同工之处。

引用法纳姆街博客上的话来解释说,心智模型就是我们大脑做决定时所用的工具箱。工具箱里有的工具越多,你就更有可能做出正确的决定。因此,心智模型是工具,也是举一反三和学习迁移的基础,其重要性不言而喻。

3. 一定要用最新,最流行的工具?

荀子在《荀子·劝学》中说:“假舟楫者,非能水也,而绝江河。君子生非异也,善假于物也。”

由此可见,善于利用已有的条件,是我们成功的一个重要途径。

同理,引申至我们的学习,工作中,同样适用。例如,在处理大量的数据统计上,使用计算器,或借助程序演算,会比口算或者笔算来得便捷高效,从而节省了多余的时间,可以投入到深度工作中去。

例如,在项目趋向稳定阶段,需求变更较小,大量重复性验证的测试工作,可以通过使用自动化工具辅助解决,从而释放了更多的人力去做更重要的事情;

设计师熟练使用各种设计软件,借助设计软件,能快速高效地完成精美的设计图;

程序员熟悉使用编程语言,能开发出各种改变人类生活方式,甚至改变世界的软件;

产品经理借助原型工具,能有效地把用户需求转换成一张张“会说话”的原型图。

可以说,在信息科技发达的今天,善于利用身边已有的条件资源进行配置,会让你事半功倍。

在尝试了使用工具便捷的甜头后,于是,我们容易掉进一个误区:追求使用最新,最流行的工具。

正所谓,水能载舟,亦能覆舟。过度依赖工具,只会适得其反。

例如,一个精通使用各种设计软件的设计师,如果一直只是在对使用工具的技巧上精进,不断在新工具,流行工具的使用上打磨,而不注重创新,不注重设计理念的提升,那么充其量也只能算是个设计“工匠”;

一个只会熟练使用编程语言的程序员,如果只是一味地追求编程技术上的精进,而不注重编程思维的提升,那么也很难以获得新的突破。

以前的一个技术总监对我们说过一番话,“技术人,不要老是埋头敲代码,要有点产品思维,要注重思想上的提升。语言只是一种工具,一种实现的手段,不要只做工具的奴隶,而要做思想上的巨人。”

特里说:“即便你拥有一种专业技能,也会潮起潮落,新的热潮会开始涌现。如果你想站在最前沿,你的思想就要变得更开阔。关键不再仅仅是找到从A点到B点的最短捷径。”

由此可见,技法固然重要,但凌驾于技法之上的,却是一个人的思想高度。

4. 最 后

在《认知天性》里有一段话,“我们之所以努力,是因为努力本身能拓展我们的能力。你所做的事情决定了你会成为什么样的人,决定了你有能力做什么。你做的事情越多,你能做的事情也就越多。”

虽然我不太苟同,在 IT 行业有所谓的‘走入死胡同的工作’。但是技术在更新,工作一直在变化,这对IT人来说是个真正的痛点。

保持终身学习的习惯,拥有可迁移的底层能力以及不断提升的思想高度,即使有一天,AI替代了现在的我们,我们依然能去制造另一个AI,BI,CI……

如何在CentOS 7 / Fedora 31/30/29上安装ELK Stack

原文地址:https://computingforgeeks.com/how-to-install-elk-stack-on-centos-fedora/

原作者: Josphat Mutai

译者:高行行

如何在 CentOS 7 / Fedora 31/30/29 上安装 ELK Stack?“ ELK ”是 Elasticsearch, Logstash, and Kibana 的缩写。

  • Elasticsearch:这是一个开源的、基于 REST 和 JSON 的搜索引擎。它具有可扩展性、易用性和灵活性
  • Logstash :这是一个服务器端数据处理管道,它同时从多个来源中采集数据,转换数据,然后将其发送到类似 Elasticsearch 的“存储”中。
  • Kibana 允许用户使用图表可视化 Elasticsearch 中的数据。

对于 RHEL 8,请参阅:

如何在 RHEL / CentOS 8 上安装 ELK Stack

请按照以下步骤在 CentOS 7 / Fedora 31/30/29 Linux 上安装和配置 ELK stack 工具。

步骤 1:安装 Java

由于 Elasticsearch 依赖 Java,因此你需要在 CentOS 7 / Fedora 系统上安装 Java。

1
sudo yum -y install java-openjdk-devel java-openjdk

步骤 2:添加 ELK 存储库

安装 Java 后,添加提供 ELK 堆栈软件包的 ELK 堆栈存储库。

对于 Elasticsearch 7.x

1
2
3
4
5
6
7
8
9
10
cat <<EOF | sudo tee /etc/yum.repos.d/elasticsearch.repo
[elasticsearch-7.x]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF

对于 Elasticsearch 6.x

1
2
3
4
5
6
7
8
9
10
cat <<EOF | sudo tee /etc/yum.repos.d/elasticsearch.repo
[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF

添加仓库后,导入 GPG 密钥:

1
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

清除并更新你的 YUM 软件包索引。

1
2
sudo yum clean all
sudo yum makecache

步骤 3:安装和配置 Elasticsearch

Elasticsearch 存储库已准备就绪,可以使用。你可以使用以下命令安装 Elasticsearch:

1
sudo yum -y install elasticsearch

确认软件包安装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ rpm -qi elasticsearch
Name : elasticsearch
Epoch : 0
Version : 7.0.1
Release : 1
Architecture: x86_64
Install Date: Mon 06 May 2019 09:59:57 PM EAT
Group : Application/Internet
Size : 571521653
License : Elastic License
Signature : RSA/SHA512, Mon 29 Apr 2019 05:14:11 PM EAT, Key ID d27d666cd88e42b4
Source RPM : elasticsearch-7.0.1-1-src.rpm
Build Date : Mon 29 Apr 2019 04:06:59 PM EAT
Build Host : packer-virtualbox-iso-1553723689
Relocations : /usr
Packager : Elasticsearch
Vendor : Elasticsearch
URL : https://www.elastic.co/
Summary : Elasticsearch is a distributed RESTful search engine built for the cloud. Reference documentation can be found at https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html and the 'Elasticsearch: The Definitive Guide' book can be found at https://www.elastic.co/guide/en/elasticsearch/guide/current/index.html
Description :
Elasticsearch subproject :distribution:packages

你可以通过编辑文件来设置 JVM 选项(例如内存限制): /etc/elasticsearch/jvm.options

下面的示例设置总堆空间的初始/最大大小

1
2
-Xms1g
-Xmx1g

如果你的系统内存较少,则可以将其配置为使用较小的内存。

1
2
-Xms256m
-Xmx512m

启动并设置为开机时启用 elasticsearch 服务:

1
2
3
4
$ sudo systemctl enable --now elasticsearch.service
Synchronizing state of elasticsearch.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable elasticsearch
Created symlink /etc/systemd/system/multi-user.target.wants/elasticsearch.service → /usr/lib/systemd/system/elasticsearch.service.

测试以验证其是否正常运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ curl http://127.0.0.1:9200
{
"name" : "localhost.localdomain",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "7fyD4TuqQ7yxog0fCnPXuA",
"version" : {
"number" : "7.5.0",
"build_flavor" : "default",
"build_type" : "rpm",
"build_hash" : "e9ccaed468e2fac2275a3761849cbee64b39519f",
"build_date" : "2019-11-26T01:06:52.518245Z",
"build_snapshot" : false,
"lucene_version" : "8.3.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

创建一个测试的索引:

1
2
$ curl -X PUT "http://127.0.0.1:9200/mytest_index"
{"acknowledged":true,"shards_acknowledged":true,"index":"mytest_index"}

步骤 4:安装和配置 Kibana

从添加的 Elasticsearch 存储库下载并安装 Kibana。

1
sudo yum -y install kibana

成功安装后,配置 Kibana:

1
2
3
4
$ sudo vim /etc/kibana/kibana.yml
server.host: "0.0.0.0"
server.name: "kibana.example.com"
elasticsearch.url: "http://localhost:9200"

根据需要更改其他设置,然后启动 kibana 服务:

1
sudo systemctl enable --now kibana

访问 http://ip-address:5601 以打开 Kibana 信息中心:

如果你有活动的防火墙服务,请允许使用 TCP 5601 端口

1
2
sudo firewall-cmd --add-port=5601/tcp --permanent
sudo firewall-cmd --reload

步骤 5:安装和配置 Logstash

最后安装的是针对 Logstash 的。它将充当客户端系统的集中式日志服务器,该服务器运行诸如filebeat之类的代理 。

1
sudo yum -y install logstash

Logstash 自定义配置可以放在 /etc/logstash/conf.d/目录下。

有关更多详细信息,请 参阅 Logstash 配置手册

步骤 6:安装其他 ELK 工具-锦上添花

可以安装的其他 ELK 工具包括:

  • Filebeat:用于日志的轻量型采集器。通过提供一种转发和汇总日志与文件的轻量级方法,让简单的事情不再繁杂。
  • Metricbeat:用于从系统和服务收集指标。Metricbeat 能够以一种轻量型的方式,输送各种系统和服务统计数据,从 CPU 到内存,从 Redis 到 Nginx,不一而足。
  • Packetbeat:轻量型网络数据采集器。用于深挖网线上传输的数据,了解应用程序动态。Packetbeat 是一款轻量型网络数据包分析器,能够将数据发送至 Logstash 或 Elasticsearch。
  • Heartbeat:用于正常运行时间监视的轻量型采集器。它通过主动探测帮助你监视服务的可用性
  • Auditbeat:轻量型审计日志采集器,可帮助你审核系统上用户和进程的活动

这些工具可以通过 yum 软件包管理器使用它们各自的名称一起进行安装。下面的示例将安装所有ELK插件工具。

1
sudo yum install filebeat auditbeat metricbeat packetbeat heartbeat-elastic

有关每种工具的配置和进一步的阅读,请参考官方的 ELK Stack 文档 以及 资源和培训

更多指南:

在 Ubuntu 上使用 Elasticsearch 6 安装 Graylog 3

在 CentOS / RHEL 8 上安装 Graylog 3

在 CentOS 7 上安装 Elasticsearch 7

目前为止全网最全的 SpringBoot 参数传递方案

原文作者:小柒2012

原文地址:https://yq.aliyun.com/articles/723593?utm_content=g_1000083974

小结:

String username, String password

SysUser user

多参数无实体一:

@RequestBody Map<String,Object> map

多参数无实体二:

@RequestParam Map<String,Object> map

数组:

@RequestParam(value = “ids[]”) Integer[] ids

集合:

@RequestParam(value = “ids[]”) List ids

集合实体对象:

@RequestBody List list

集合实体对象一对多:

@RequestBody List list

  • @RequestBody 注解,必须与 contentType 类型application/json配合使用。

  • @RequestParam 注解,必须与 contentType 类型application/x-www-form-urlencoded配合使用,其为默认类型。

  • JSON.stringify() 把对象类型转换为字符串类型,一般配合 @RequestBody 注解和contentType 类型application/json使用。

1. 前言

开发这么多年,肯定还有不少小伙伴搞不清各种类型的参数是如何传递的,很多同学都是拿来即用,复制粘贴一把撸,遇到问题还是一脸懵逼。

2. 姿势

学习参数传递的正确姿势,先说怎么做,再说为什么,本质上还是复制粘贴一把撸,问题是你想问不想问为什么!

3. 传递

用户登录

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
var param = {
"username": "admin",
"password": "admin"
}
$.ajax({
url: "/sys/login",
data: param,
type: "post",
dataType: "json",
success: function(data) {

}
});

后端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@RequestMapping("/sys")
public class LoginController {

private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

/**
* 登录
*/
@PostMapping("/login")
public Result login(String username, String password){
logger.info("用户登录"+username);
//业务逻辑
return Result.ok("登录成功");
}
}

当然,你也可以这么实现,@RequestParam(value="username", required=true)required 默认为 true,如果前台不传递此参数,后台会报错。如果设置为 false,如果不传,默认为 null

1
2
3
4
5
6
7
8
9
10
11
/**
* 登录
* https://blog.52itstyle.vip
*/
@PostMapping("/login")
public Result login(@RequestParam(value="username", required=true) String username,
@RequestParam(value="password", required=true) String password){
logger.info("用户登录"+username);
//业务逻辑
return Result.ok("登录成功");
}

用户注册

前端代码,提交方式与登录基本保持一致。

后端代码:

用一个对象来接收前台参数,一般后端有对应的实体类。

1
2
3
4
5
6
7
8
9
10
/**
* 注册
* https://blog.52itstyle.vip
*/
@PostMapping("/register")
public Result register(SysUser user){
logger.info("{},用户注册",user.getUsername());
//业务逻辑
return Result.ok("注册成功");
}

多参数无实体一

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var param = {
"title": "爪哇笔记",
"content": "一个有趣的公众号",
"author": "小柒2012"
}
param = JSON.stringify(param);
$.ajax({
url: "/sys/multiParameter",
data: param,
type: "post",
contentType: "application/json",
dataType: "json",
success: function(data) {

}
});

后端实现:

1
2
3
4
5
6
7
8
9
10
/**
* 多参数
* https://blog.52itstyle.vip
*/
@PostMapping("/multiParameter")
public Result register(@RequestBody Map<String,Object> map){
logger.info("多参数传递:{},{}",map.get("title"),map.get("content"));
//业务逻辑
return Result.ok("接收多参数成功");
}

多参数无实体二

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var param = {
"title": "爪哇笔记",
"content": "一个有趣的公众号",
"author": "小柒2012"
}
$.ajax({
url: "/sys/multiParameter",
data: param,
type: "post",
dataType: "json",
success: function(data) {

}
});

后端实现:

1
2
3
4
5
6
7
8
9
10
/**
* 多参数
* https://blog.52itstyle.vip
*/
@PostMapping("/multiParameter")
public Result register(@RequestParam Map<String,Object> map){
logger.info("多参数传递:{},{}",map.get("title"),map.get("content"));
//业务逻辑
return Result.ok("接收多参数成功");
}

传递数组

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
var param = {
"ids": [1, 2, 3]
}
$.ajax({
url: "/sys/array",
data: param,
type: "post",
dataType: "json",
success: function(data) {

}
});

后端实现:

1
2
3
4
5
6
7
8
9
10
/**
* 数组
* https://blog.52itstyle.vip
*/
@PostMapping("array")
public Result array(@RequestParam(value = "ids[]") Integer[] ids) {
logger.info("数据{}", Arrays.asList(ids));
//业务逻辑
return Result.ok();
}

传递集合

前端代码与传递数组保持一致。

后端实现:

1
2
3
4
5
6
7
8
9
10
/**
* 集合
* https://blog.52itstyle.vip
*/
@PostMapping("array")
public Result array(@RequestParam(value = "ids[]") List<Integer> ids) {
logger.info("数据{}", ids.toString());
//业务逻辑
return Result.ok();
}

传递集合实体对象

比如,后端想接收一个实体对象集合 List

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var list = [];
list.push({
"username": "小柒2012",
"mobile": "17762288888"
});
list.push({
"username": "小柒2013",
"mobile": "17762289999"
});
$.ajax({
url: "/sys/listUser",
data: JSON.stringify(list),
type: "post",
contentType: "application/json",
dataType: "json",
success: function(data) {

}
});

后端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 爪哇笔记
* https://blog.52itstyle.vip
*/
@PostMapping("listUser")
public Result listUser(@RequestBody List<SysUser> list) {
logger.info("数据{}", list.size());
list.forEach(user->{
//输出实体对象
System.out.println(user.getUsername());
});
//业务逻辑
return Result.ok();
}

传递集合实体对象一对多

比如,一个用户有多个角色 List roleList

前端代码:

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
var roleList = [];
roleList.push({
"roleSign": "admin",
"roleName": "管理员"
});
roleList.push({
"roleSign": "user",
"roleName": "普通用户"
});
var list = [];
var user = {
"username": "小柒2012",
"mobile": "17762288888"
};
user.roleList = roleList;
list.push(user);
$.ajax({
url: "/sys/listUserRole",
data: JSON.stringify(list),
type: "post",
contentType: "application/json",
dataType: "json",
success: function(data) {

}
});

后端实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 爪哇笔记
* https://blog.52itstyle.vip
*/
@PostMapping("listUserRole")
public Result listUserRole(@RequestBody List<SysUser> list) {
logger.info("数据{}", list.size());
list.forEach(user->{
List<SysRole> roleList = user.getRoleList();
roleList.forEach(role->{
System.out.println(role.getRoleName());
});
});
return Result.ok();
}

炒鸡复杂

传输对象有实体,有集合,有各种类型的数据,这时候最简单的方式就是传递 Key-Value 结构的 JSON 字符串,后台 Map 类型接收,然后通过FastJsonJSON.parseObject()JSON.parseArray() 方法转化为对应的实体或者集合。

1
2
3
4
String user = parseMap.get("user").toString();
SysUser sysUser = JSON.parseObject(user,SysUser.class);
String contractClause = parseMap.get("rules").toString();
List<Rule> ruleList = JSON.parseArray(contractClause,Rule.class);

RESTful 风格

比如,访问某篇文章:

1
2
3
4
5
6
7
8
9
/**
* 爪哇笔记
* https://blog.52itstyle.vip
*/
@GetMapping("article/{id}")
public void article(@PathVariable("id") String id) {
logger.info("文章{}",id);
//业务逻辑
}

4. 原则

记住以下几点:

  • @RequestBody 注解,必须与 contentType 类型application/json配合使用。
  • @RequestParam 注解,必须与 contentType 类型application/x-www-form-urlencoded配合使用,其为默认类型。
  • JSON.stringify() 把对象类型转换为字符串类型,一般配合 @RequestBody 注解和contentType 类型application/json使用。

扩展

在以上只涉及了两种 contentType 类型,其实还有两种常见的类型:

multipart/form-data

一般用于表单文件上传,必须让 form 的 enctype 等于这个值。

1
2
3
4
5
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="text" name="description" value="爪哇笔记,一个神奇的公众号">
<input type="file" name="myFile">
<button type="submit">Submit</button>
</form>

text/xml

做过微信支付的小伙伴一定会知道,微信就喜欢用这种方式,去年还发生过 XXE 漏洞,在解析XML文档时,解析器通过 ENTITY 扩展的功能,读取本地受保护的文件,并且使用扩展功能将受保护的文件发送到远程地址。

小结

不敢说是最完整的传参方案,但绝对敢保证是最正确的,因为所有的传参方式都经过 360° 官方检验。

  • Copyrights © 2015-2023 高行行
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信