我这样写代码,比直接使用 MyBatis 效率提高了 100 倍

news2024/9/22 11:25:40

对一个 Java 后端程序员来说,mybatis、hibernate、data-jdbc 等都是我们常用的 ORM 框架。它们有时候很好用,比如简单的 CRUD,事务的支持都非常棒。但有时候用起来也非常繁琐,比如接下来我们要聊到的一个常见的开发需求,而对这类需求,本文会给出一个比直接使用这些 ORM 开发效率至少会提高 100 倍的方法(绝无夸张)。

首先数据库有两张表

用户表(user):(简单起见,假设只有 4 个字段)

字段名

类型

含义

id

bitint

用户 ID

name

varchar(45)

用户名

age

int

年龄

role_id

int

角色 ID

角色表(role):(简单起见,假设只有 2 个字段)

字段名

类型

含义

id

int

角色 ID

name

varchar(45)

角色名

接下来我们要实现一个用户查询的功能

这个查询有点复杂,它的要求如下:

  • 可按用户名字段查询,要求: 可精确匹配(等于某个值) 可全模糊匹配(包含给定的值) 可后模糊查询(以...开头) 可前模糊查询(以.. 结尾) 可指定以上四种匹配是否可以忽略大小写

  • 可按年龄字段查询,要求: 可精确匹配(等于某个年龄) 可大于匹配(大于某个值) 可小于匹配(小于某个值) 可区间匹配(某个区间范围)

  • 可按角色ID查询,要求:精确匹配

  • 可按用户ID查询,要求:同年龄字段

  • 可指定只输出哪些列(例如,只查询 ID 与 用户名 列)

  • 支持分页(每次查询后,页面都要显示满足条件的用户总数)

  • 查询时可选择按 ID、用户名、年龄 等任意字段排序

后端接口该怎么写呢?

试想一下,对于这种要求的查询,后端接口里的代码如果用 mybatis、hibernate、data-jdbc 直接来写的话,100 行代码 能实现吗?

反正我是没这个信心,算了,我还是直接坦白,面对这种需求后端如何 只用一行代码搞定 吧(有兴趣的同学可以 mybatis 等写个试试,最后可以对比一下)

手把手:只一行代码实现以上需求

首先,重点人物出场啦:Bean Searcher, 它就是专门来对付这种列表检索的,无论简单的还是复杂的,统统一行代码搞定!而且它还非常轻量,Jar 包体积仅不到 100KB,无第三方依赖。

假设我们项目使用的框架是 Spring Boot(当然 Bean Searcher 对框架没有要求,但在 Spring Boot 中使用更加方便)

添加依赖

Maven :

 
 

<dependency> <groupId>com.ejlchina</groupId> <artifactId>bean-searcher-boot-starter</artifactId> <version>3.0.1</version> </dependency>

Gradle :

 
 

implementation 'com.ejlchina:bean-searcher-boot-starter:3.0.1'

然后写个实体类来承载查询的结果

 
 

@SearchBean(tables="user u, role r", joinCond="u.role_id = r.id", autoMapTo="u") public class User { private Long id; // 用户ID(u.id) private String name; // 用户名(u.name) private int age; // 年龄(u.age) private int roleId; // 角色ID(u.role_id) @DbField("r.name") // 指明这个属性来自 role 表的 name 字段 private int role; // 角色名(r.name) // Getter and Setter ... }

接着就可以写用户查询接口了

接口路径就叫 /user/index 吧:

 
 

@RestController @RequestMapping("/user") public class UserController { @Autowired private MapSearcher mapSearcher; // 注入检索器(由 bean-searcher-boot-starter 提供) @GetMapping("/index") public SearchResult<Map<String, Object>> index(HttpServletRequest request) { // 这里咱们只写一行代码 return mapSearcher.search(User.class, MapUtils.flat(request.getParameterMap())); } }

上述代码中的 MapUtils 是 Bean Searcher 提供的一个工具类,MapUtils.flat(request.getParameterMap()) 只是为了把前端传来的请求参数统一收集起来,然后剩下的,就全部交给 MapSearcher 检索器了。

这样就完了?那我们来测一下这个接口,看看效果吧

(1)无参请求

  • GET /user/index

  • 返回结果:

 
 

{ "dataList": [ // 用户列表,默认返回第 0 页,默认分页大小为 15 (可配置) { "id": 1, "name": "Jack", "age": 25, "roleId": 1, "role": "普通用户" }, { "id": 2, "name": "Tom", "age": 26, "roleId": 1, "role": "普通用户" }, ... ], "totalCount": 100 // 用户总数 }

(2)分页请求(page | size)

  • GET /user/index? page=2 & size=10

  • 返回结果:结构同 (1)(只是每页 10 条,返回第 2 页)

参数名 size 和 page 可自定义, page 默认从 0 开始,同样可自定义,并且可与其它参数组合使用

(3)数据排序(sort | order)

  • GET /user/index? sort=age & order=desc

  • 返回结果:结构同 (1)(只是 dataList 数据列表以 age 字段降序输出)

参数名 sort 和 order 可自定义,可与其它参数组合使用

(4)指定(排除)字段(onlySelect | selectExclude)

  • GET /user/index? onlySelect=id,name,role

  • GET /user/index? selectExclude=age,roleId

  • 返回结果:( 列表只含 id,name 与 role 三个字段)

 
 

{ "dataList": [ // 用户列表,默认返回第 0 页(只包含 id,name,role 字段) { "id": 1, "name": "Jack", "role": "普通用户" }, { "id": 2, "name": "Tom", "role": "普通用户" }, ... ], "totalCount": 100 // 用户总数 }

参数名 onlySelect 和 selectExclude 可自定义,可与其它参数组合使用

(5)字段过滤(op = eq)

  • GET /user/index? age=20

  • GET /user/index? age=20 & age-op=eq

  • 返回结果:结构同 (1)(但只返回 age = 20 的数据)

参数 age-op = eq 表示 age 的 字段运算符 是 eq(Equal 的缩写),表示参数 age 与参数值 20 之间的关系是 Equal,由于 Equal 是一个默认的关系,所以 age-op = eq 也可以省略

参数名 age-op 的后缀 -op 可自定义,且可与其它字段参数 和 上文所列的参数(分页、排序、指定字段)组合使用,下文所列的字段参数也是一样,不再复述。

(6)字段过滤(op = ne)

  • GET /user/index? age=20 & age-op=ne

  • 返回结果:结构同 (1)(但只返回 age != 20 的数据,ne 是 NotEqual 的缩写)

(7)字段过滤(op = ge)

  • GET /user/index? age=20 & age-op=ge

  • 返回结果:结构同 (1)(但只返回 age >= 20 的数据,ge 是 GreateEqual 的缩写)

(8)字段过滤(op = le)

  • GET /user/index? age=20 & age-op=le

  • 返回结果:结构同 (1)(但只返回 age <= 20 的数据,le 是 LessEqual 的缩写)

(9)字段过滤(op = gt)

  • GET /user/index? age=20 & age-op=gt

  • 返回结果:结构同 (1)(但只返回 age > 20 的数据,gt 是 GreateThan 的缩写)

(10)字段过滤(op = lt)

  • GET /user/index? age=20 & age-op=lt

  • 返回结果:结构同 (1)(但只返回 age < 20 的数据,lt 是 LessThan 的缩写)

(11)字段过滤(op = bt)

  • GET /user/index? age-0=20 & age-1=30 & age-op=bt

  • 返回结果:结构同 (1)(但只返回 20 <= age <= 30 的数据,bt 是 Between 的缩写)

参数 age-0 = 20 表示 age 的第 0 个参数值是 20。上述提到的 age = 20 实际上是 age-0 = 20 的简写形式。另:参数名 age-0 与 age-1 中的连字符 - 可自定义。

(12)字段过滤(op = mv)

  • GET /user/index? age-0=20 & age-1=30 & age-2=40 & age-op=mv

  • 返回结果:结构同 (1)(但只返回 age in (20, 30, 40) 的数据,mv 是 MultiValue 的缩写,表示有多个值的意思)

(13)字段过滤(op = in)

  • GET /user/index? name=Jack & name-op=in

  • 返回结果:结构同 (1)(但只返回 name 包含 Jack 的数据,in 是 Include 的缩写)

(14)字段过滤(op = sw)

  • GET /user/index? name=Jack & name-op=sw

  • 返回结果:结构同 (1)(但只返回 name 以 Jack 开头的数据,sw 是 StartWith 的缩写)

(15)字段过滤(op = ew)

  • GET /user/index? name=Jack & name-op=ew

  • 返回结果:结构同 (1)(但只返回 name 以 Jack 结尾的数据,sw 是 EndWith 的缩写)

(16)字段过滤(op = ey)

  • GET /user/index? name-op=ey

  • 返回结果:结构同 (1)(但只返回 name 为空 或为 null 的数据,ey 是 Empty 的缩写)

(17)字段过滤(op = ny)

  • GET /user/index? name-op=ny

  • 返回结果:结构同 (1)(但只返回 name 非空 的数据,ny 是 NotEmpty 的缩写)

(18)忽略大小写(ic = true)

  • GET /user/index? name=Jack & name-ic=true

  • 返回结果:结构同 (1)(但只返回 name 等于 Jack (忽略大小写) 的数据,ic 是 IgnoreCase 的缩写)

参数名 name-ic 中的后缀 -ic 可自定义,该参数可与其它的参数组合使用,比如这里检索的是 name 等于 Jack 时忽略大小写,但同样适用于检索 name 以 Jack 开头或结尾时忽略大小写。

当然,以上各种条件都可以组合,例如

查询 name 以 Jack (忽略大小写) 开头,且 roleId = 1,结果以 id 字段排序,每页加载 10 条,查询第 2 页:

  • GET /user/index? name=Jack & name-op=sw & name-ic=true & roleId=1 & sort=id & size=10 & page=2

  • 返回结果:结构同 (1)

OK,效果看完了,/user/index 接口里我们确实只写了一行代码,它便可以支持这么多种的检索方式,有没有觉得现在 你写的一行代码 就可以 干过别人的一百行 呢?

编辑切换为居中

添加图片注释,不超过 140 字(可选)

Bean Searcher

本例中,我们只使用了 Bean Searcher 提供的 MapSearcher 检索器的一个 search 方法,其实,它有很多 search 方法。

检索方法

  • searchCount(Class<T> beanClass, Map<String, Object> params) 查询指定条件下的数据 总条数

  • searchSum(Class<T> beanClass, Map<String, Object> params, String field) 查询指定条件下的 某字段 的 统计值

  • searchSum(Class<T> beanClass, Map<String, Object> params, String[] fields) 查询指定条件下的 多字段 的 统计值

  • search(Class<T> beanClass, Map<String, Object> params) 分页 查询指定条件下数据 列表 与 总条数

  • search(Class<T> beanClass, Map<String, Object> params, String[] summaryFields) 同上 + 多字段 统计

  • searchFirst(Class<T> beanClass, Map<String, Object> params) 查询指定条件下的 第一条 数据

  • searchList(Class<T> beanClass, Map<String, Object> params) 分页 查询指定条件下数据 列表

  • searchAll(Class<T> beanClass, Map<String, Object> params) 查询指定条件下 所有 数据 列表

MapSearcher 与 BeanSearcher

另外,Bean Searcher 除了提供了 MapSearcher 检索器外,还提供了 BeanSearcher 检索器,它同样拥有 MapSearcher 拥有的方法,只是它返回的单条数据不是 Map,而是一个 泛型 对象。

参数构建工具

另外,如果你是在 Service 里使用 Bean Searcher,那么直接使用 Map<String, Object> 类型的参数可能不太优雅,为此, Bean Searcher 特意提供了一个参数构建工具。

例如,同样查询 name 以 Jack (忽略大小写) 开头,且 roleId = 1,结果以 id 字段排序,每页加载 10 条,加载第 2 页,使用参数构建器,代码可以这么写:

 
 

Map<String, Object> params = MapUtils.builder() .field(User::getName, "Jack").op(Operator.StartWith).ic() .field(User::getRoleId, 1) .orderBy(User::getId, "asc") .page(2, 10) .build() List<User> users = beanSearcher.searchList(User.class, params);

这里使用的是 BeanSearcher 检索器,以及它的 searchList(Class<T> beanClass, Map<String, Object> params) 方法。

运算符约束

上文我们看到,Bean Searcher 对实体类中的每一个字段,都直接支持了很多的检索方式。

但某同学:哎呀!检索方式太多了,我根本不需要这么多,我的数据量几十亿,用户名字段的前模糊查询方式利用不到索引,万一把我的数据库查崩了怎么办呀?

好办,Bean Searcher 支持运算符的约束,实体类的用户名 name 字段只需要注解一下即可:

 
 

@SearchBean(tables="user u, role r", joinCond="u.role_id = r.id", autoMapTo="u") public class User { @DbField(onlyOn = {Operator.Equal, Operator.StartWith}) private String name; // 为减少篇幅,省略其它字段... }

如上,通过 @DbField 注解的 onlyOn 属性,指定这个用户名 name 只能适用与 精确匹配 和 后模糊查询,其它检索方式它将直接忽略。

上面的代码是限制了 name 只能有两种检索方式,如果再严格一点,只允许 精确匹配,那其实有两种写法。

(1)还是使用运算符约束:

 
 

@SearchBean(tables="user u, role r", joinCond="u.role_id = r.id", autoMapTo="u") public class User { @DbField(onlyOn = Operator.Equal) private String name; // 为减少篇幅,省略其它字段... }

(2)在 Controller 的接口方法里把运算符参数覆盖:

 
 

@GetMapping("/index") public SearchResult<Map<String, Object>> index(HttpServletRequest request) { Map<String, Object> params = MapUtils.flatBuilder(request.getParameterMap()) .field(User::getName).op(Operator.Equal) // 把 name 字段的运算符直接覆盖为 Equal .build() return mapSearcher.search(User.class, params); }

条件约束

该同学又:哎呀!我的数据量还是很大,age 字段没有索引,我不想让它参与 where 条件,不然很可能就出现慢 SQL 啊!

不急,Bean Searcher 还支持条件的约束,让这个字段直接不能作为条件:

 
 

@SearchBean(tables="user u, role r", joinCond="u.role_id = r.id", autoMapTo="u") public class User { @DbField(conditional = false) private int age; // 为减少篇幅,省略其它字段... }

如上,通过 @DbField 注解的 conditional 属性, 就直接不允许 age 字段参与条件了,无论前端怎么传参,Bean Searcher 都不搭理。

参数过滤器

该同学仍:哎呀!哎呀 ...

别怕! Bean Searcher 还支持配置全局参数过滤器,可自定义任何参数过滤规则,在 Spring Boot 项目中,只需要配置一个 Bean:

 
 

@Bean public ParamFilter myParamFilter() { return new ParamFilter() { @Override public <T> Map<String, Object> doFilter(BeanMeta<T> beanMeta, Map<String, Object> paraMap) { // beanMeta 是正在检索的实体类的元信息, paraMap 是当前的检索参数 // TODO: 这里可以写一些自定义的参数过滤规则 return paraMap; // 返回过滤后的检索参数 } }; }

某同学问

参数咋这么怪,这么多呢,和前端有仇么

  1. 参数名是否奇怪,这其实看个人喜好,如果你不喜欢中划线 -,不喜欢 op、ic 后缀,完全可以自定义,参考这篇文档:

searcher.ejlchina.com/guide/lates…

  1. 参数个数的多少,其实是和需求的复杂程度相关的。如果需求很简单,那么很多参数没必要让前端传,后端直接塞进去就好。比如:name 只要求后模糊匹配,age 只要求区间匹配,则可以:

 
 

@GetMapping("/index") public SearchResult<Map<String, Object>> index(HttpServletRequest request) { Map<String, Object> params = MapUtils.flatBuilder(request.getParameterMap()) .field(User::getName).op(Operator.StartWith) .field(User::getAge).op(Operator.Between) .build() return mapSearcher.search(User.class, params); }

这样前端就不用传 name-op 与 age-op 这两个参数了。

其实还有一种更简单的方法,那就是 运算符约束(当约束存在时,运算符默认就是 onlyOn 属性中指定的第一个值,前端可以省略不传):

 
 

@SearchBean(tables="user u, role r", joinCond="u.role_id = r.id", autoMapTo="u") public class User { @DbField(onlyOn = Operator.StartWith) private String name; @DbField(onlyOn = Operator.Between) private String age; // 为减少篇幅,省略其它字段... }

入参是 request,我 swagger 文档不好渲染了呀

其实,Bean Searcher 的检索器只是需要一个 Map<String, Object> 类型的参数,至于这个参数是怎么来的,和 Bean Searcher 并没有直接关系。前文之所以从 request 里取,只是因为这样代码看起来简洁,如果你喜欢声明参数,完全可以把代码写成这样:

 
 

@GetMapping("/index") public SearchResult<Map<String, Object>> index(Integer page, Integer size, String sort, String order, String name, Integer roleId, @RequestParam(value = "name-op", required = false) String name_op, @RequestParam(value = "name-ic", required = false) Boolean name_ic, @RequestParam(value = "age-0", required = false) Integer age_0, @RequestParam(value = "age-1", required = false) Integer age_1, @RequestParam(value = "age-op", required = false) String age_op) { Map<String, Object> params = MapUtils.builder() .field(Employee::getName, name).op(name_op).ic(name_ic) .field(Employee::getAge, age_0, age_1).op(age_op) .field(Employee::getRoleId, roleId) .orderBy(sort, order) .page(page, size) .build(); return mapSearcher.search(User.class, params); }

结语

本文介绍了 Bean Searcher 在复杂列表检索领域的超强能力。它之所以可以极大提高这类需求的研发效率,根本上归功于它 独创 的 动态字段运算符 与 多表映射机制,这是传统 ORM 框架所没有的。但由于篇幅所限,它的特性本文不能尽述,比如它还:

  • 支持 聚合查询

  • 支持 Select|Where|From子查询

  • 支持 实体类嵌入参数

  • 支持 字段转换器

  • 支持 Sql 拦截器

  • 支持 多数据源

  • 支持 自定义注解

  • 等等

要了解更多,先来点个 Star 吧 : Github 、Gitee。

Bean Searcher 是我在工作中总结封装出来的一个小工具,公司内部使用了 4 年,经历大小项目三四十个,只是最近才着手完善文档分享给大家,如果你喜欢,一定去点个 Star 哦 ^_^。

再奉上 Bean Searcher 的详细文档:searcher.ejlchina.com/

最后,再来个 Demo 地址:

  • Spring Boot 框架中使用 demo

  • github.com/ejlchina/be…

  • gitee.com/ejlchina-zh…

  • Grails 框架中使用 demo

  • github.com/ejlchina/be…

  • gitee.com/ejlchina-zh…


代码,也喜欢纯手工的,因为这样才能造出真正的艺术品。

                             资源获取:

大家点赞、收藏、关注、评论啦 、查看👇🏻👇🏻👇🏻微信公众号获取联系方式👇🏻👇🏻👇🏻

 精彩专栏推荐订阅:下方专栏👇🏻👇🏻👇🏻👇🏻

每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/32968.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【知识图谱论文】调整元知识图信息以在少样本关系上进行多跳推理

文章题目&#xff1a;Adapting Meta Knowledge Graph Information for Multi-Hop Reasoning over Few-Shot Relations时间&#xff1a;2019 摘要 多跳知识图 (KG) 推理是一种有效且可解释的方法&#xff0c;用于在查询回答 (QA) 任务中通过推理路径预测目标实体。 大多数以前…

做交互设计都有哪些需要掌握的思维方式

由于目前的环境对这个细分领域仍然缺乏了解&#xff0c;我希望在这篇文章中写一些交互设计所需的思维方式。 ​ 1.可用性优先&#xff0c;视觉靠边 一个功能个功能应该能够使用和使用&#xff0c;以便有人关心它是否好看。审美挑剔的用户实际上比你想象的要少得多。当然&#…

机械工程基础知识点汇总

第一章 常用机构 一、零件、构件、部件 零件&#xff0c;是指机器中每一个最基本的制造单元体。 在机器中&#xff0c;由一个或几个零件所构成的运动单元体&#xff0c;称为构件。 部件&#xff0c;指机器中由若干零件所组成的装配单元体。 二、机器、机构、机械 机器具有以下特…

智能捡乒乓球机器人

本文素材来源于物理与电子电气工程学院 作者&#xff1a;丁文龙 、王小军、任剑杰、张钊铭 指导老师&#xff1a;康彩 一、项目简介 随着人们对机器人技术智能化本质认识的加深&#xff0c;机器人技术开始源源不断地向人类活动的各个领域渗透。在这其中&#xff0c;服务机器人…

数字图像处理(十二)最大熵算法

文章目录前言一、熵是什么&#xff1f;1.信息量如何计算&#xff1f;2.熵如何计算&#xff1f;二、最大熵方法1.设计思想2.算法步骤3.C代码4.实验结果参考资料前言 在图像分析中&#xff0c;通常需要将所关心的目标从图像中提取出来&#xff0c;这种从图像中某个特定区域与其他…

JAVA中的集合类型的理解及应用

目录 概述 List和Queue Map和Set HashTable和HashMap的区别 Queue和Deque BlockingQueue 并发集合 概述 写程序免不了处理一些批量数据&#xff0c;不同数据结构和算法&#xff0c;会带来不同的性能效果。大学的计算机课程中就有一门叫《数据结构》的课程&#xff0c;这门…

总结我的 MySQL 学习历程,给有需要的人看

作者| 慕课网精英讲师 马听 你好&#xff0c;我是马听&#xff0c;现在是某零售公司的 MySQL DBA&#xff0c;身处一线的我表示有很多话要讲。 我的MySQL学习历程 在我大三的时候&#xff0c;就开始接触到 MySQL 了&#xff0c;当时我也是从最基础的 MySQL 知识&#xff08;…

6、项目第六阶段——用户名登录显示和注册验证码

第六阶段——用户名登录显示和注册验证码 1、登陆—显示用户名 UserServlet 程序中保存用户登录的信息 UserServlet程序中&#xff1a; //保存用户登录信息到Session域中 req.getSession().setAttribute("user",loginUser);修改 login_succuess_menu.jsp&#xf…

2019 国际大学生程序设计竞赛(ICPC)亚洲区域赛(银川) 7题

文章目录N.Fibonacci SequenceB.So EasyI.Base62G.Pot!!F.Function!K.Largest Common Submatrix补题链接&#xff1a;https://codeforces.com/gym/104021 难得VP打出这么好的成绩&#xff0c;虽然是有争议的西部枢纽银川站&#xff0c;虽然没能早生几年。。。。 N.Fibonacci Se…

【数据结构】基础:堆

【数据结构】基础&#xff1a;堆 摘要&#xff1a;本文主要介绍数据结构堆&#xff0c;分别介绍其概念、实现和应用。 文章目录【数据结构】基础&#xff1a;堆一、概述1.1 概念1.2 性质二、实现2.1 定义2.2 初始化与销毁2.3 入堆2.4 出堆2.5 堆的创建2.6 其他三、应用3.1 堆排…

《前端》css总结(下)

文章目录元素展示格式displaywhite-spacetext-overflowoverflow内边距和外边距marginpadding盒子模型box-sizing位置position&#xff1a;用于指定一个元素在文档中的定位方式浮动flex布局flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-contentorderflex-g…

你最少用几行代码实现深拷贝?

问题分析 深拷贝 自然是 相对 浅拷贝 而言的。 我们都知道 引用数据类型 变量存储的是数据的引用&#xff0c;就是一个指向内存空间的指针&#xff0c; 所以如果我们像赋值简单数据类型那样的方式赋值的话&#xff0c;其实只能复制一个指针引用&#xff0c;并没有实现真正的数…

计算机组成原理4小时速成:存储器,内存ROM,RAM,Cache,高速缓存cache,外存,缓存命中率,效率

计算机组成原理4小时速成&#xff1a;存储器&#xff0c;内存ROM,RAM,Cache&#xff0c;高速缓存cache&#xff0c;外存&#xff0c;缓存命中率&#xff0c;效率 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法…

MYSQL事务原理分析

目录事务是什么ACID特性原子性&#xff08;A&#xff09;隔离性&#xff08;I&#xff09;持久性&#xff08;D&#xff09;一致性&#xff08;C&#xff09;隔离级别简介有些什么READ UNCOMMITTED&#xff08;读未提交&#xff09;READ COMMITTED&#xff08;读已提交&#xf…

【17】Java常见的面试题汇总(设计模式)

目录 1. 说一下你熟悉的设计模式&#xff1f; 2. 简单工厂和抽象工厂有什么区别&#xff1f; 1. 说一下你熟悉的设计模式&#xff1f; 单例模式&#xff1a;保证被创建一次&#xff0c;节省系统开销。 工厂模式&#xff08;简单工厂、抽象工厂&#xff09;&#xff1a;解耦…

力扣(LeetCode)60. 排列序列(C++)

枚举 枚举每一位可能的数字。 如图。算法流程如上图。 思路分析 : 一个数 nnn &#xff0c;可以组成的排列数量有 n!n!n! 。当首位确定&#xff0c;剩余位能组成的排列数量 (n−1)!(n-1)!(n−1)! &#xff0c;依次类推 (n−2)!/(n−3)!/(n−4)!/…/2!/1!/0!(n-2)!/(n-3)!/(n…

CentOS7安装MYSQL8.X的教程详解

1-首先查看系统是否存在mysql&#xff0c;无则不返回 1 # rpm -qa|grep mysql 2-安装wget 1 # yum -y install wget 3-抓取mariadb并删除包&#xff0c;无则不返回 1 # rpm -qa|grep mariadb 4-删除mariadb-libs-5.5.68-1.el7.x86_64 1 # rpm -e --nodeps mariadb-libs-…

本节作业之数组求和及其平均值、求数组最大值、最小值、数组转换为分割字符串、新增数组案例、筛选数组案例、删除指定数组元素、翻转数组、数组排序(冒泡排序)

本节作业之数组求和及其平均值、求数组最大值、最小值、数组转换为分割字符串、新增数组案例、筛选数组案例、删除指定数组元素、翻转数组、数组排序<冒泡排序>求数组[2,6,1,7,4]里面所有的元素的和以及平均值求数组[2,6,1,77,52,25,7]中的最大值求数组[2,6,1,77,52,25,7…

Linux - netstat 查看系统端口占用和监听情况

文章目录功能语法示例显示 tcp&#xff0c;udp 的端口和进程Show both listening and non-listening socketsList all tcp ports.List all udp portsList only listening portsList only listening TCP ports.List only listening UDP ports.List only the listening UNIX port…

Android 性能优化方法论【总结篇】

作为一位多年长期做性能优化的开发者&#xff0c;在这篇文章中对性能优化的方法论做一些总结&#xff0c;以供大家借鉴。 性能优化的本质 首先&#xff0c;我先介绍一下性能优化的本质。我对其本质的认知是这样的&#xff1a;性能优化的本质是合理且充分的使用硬件资源&#x…