Mybatis行为配置之Ⅱ—结果相关配置项说明

专栏精选

引入Mybatis

Mybatis的快速入门

Mybatis的增删改查扩展功能说明

mapper映射的参数和结果

Mybatis复杂类型的结果映射

Mybatis基于注解的结果映射

Mybatis枚举类型处理和类型处理器

再谈动态SQL

文章目录

  • 专栏精选
  • 引言
  • 摘要
  • 正文
      • autoMappingBehavior
      • autoMappingUnknownColumnBehavior
      • lazyLoadingEnabled
      • aggressiveLazyLoading
      • lazyLoadTriggerMethods
      • multipleResultSetsEnabled
      • useColumnLabel
      • useGeneratedKeys
      • mapUnderscoreToCamelCase
  • 总结

引言

大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。欢迎来到我的频道,这里汇聚了汇集编程技巧、代码示例和技术教程,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 🙆,期待在这里与你共同度过美好的时光🕹️。今天要和大家分享的内容是行为配置之Ⅱ—结果映射配置项说明。做好准备,Let’s go🚎🚀

摘要

在这篇文章中,我们将了解Mybatis的配置将如何影响结果映射的行为,其中,有的配置项很常见,有的配置项不常见,这些配置项会对我们的开发工作造成什么样的影响,我们又将如何通过修改这些配置来简化日常开发工作呢?准备好开启今天的神奇之旅吧

正文

首图

在Mybatis的行为配置项中,存在一系列的配置项用于控制Mybatis的结果映射行为,下面我们来一一介绍这些配置项

autoMappingBehavior

备注:设置如何将字段映射行为属性,可以在NONE、PARTIAL、FULL三个可选项中选择
默认值:PARTIAL
建议值:
建议原因:
选项说明:

配置说明
NONE不自动映射,必须通过 <resultMap>标签手动指定映射
PAERIAL只会自动映射没有定义嵌套结果映射的字段
FULL自动映射任何复杂的结果集(无论是否嵌套)

可通过一下代码测试NONE配置的行为

@Test  
public void testAutoMapBehavior() {  SqlSession session = this.sqlSessionFactory.openSession();  ApplicationRepository mapper = session.getMapper(ApplicationRepository.class);  AppTestEntity e1 = mapper.queryById(1L);  System.out.println(e1);
}

默认配置下的打印结果

AppTestEntity{id=1, appName='测试应用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='null', authTypeDict=null, appStatusDict=null, services=null}

配置 <setting name="autoMappingBehavior" value="NONE"/>下的打印结果

null

如果通过 resultMap的方式指定映射关系,在NONE配置下也能成功映射

添加resultMap映射

<resultMap id="appTestMap" type="top.sunyog.common.entity.AppTestEntity">  <result column="app_name" property="appName"/>  <result column="app_code" property="appCode"/>  <result column="auth_type" property="authType"/>  <result column="create_date" property="createDate"/>  
</resultMap><!--省略sql-->
<select id="queryById" resultMap="appTestMap">...</select>

配置 <setting name="autoMappingBehavior" value="NONE"/>下的打印结果

AppTestEntity{id=null, appName='测试应用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='null', appStatus='null', authTypeDict=null, appStatusDict=null, services=null}

注意:只有result标签指明的字段才能正确映射,没指明的不会映射出结果。

细节:这里可以通过 autoMapping属性实现局部的自动映射,来改变 autoMappingBehavior的配置行为

<resultMap id="appTestMap" type="top.sunyog.common.entity.AppTestEntity" autoMapping="true">
...
</resultMap>

配置 <setting name="autoMappingBehavior" value="NONE"/>下的打印结果

AppTestEntity{id=1, appName='测试应用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='3', authTypeDict=null, appStatusDict=null, services=null}

可以通过以下代码测试FULL配置的行为

public interface ApplicationRepository {AppVo queryAppVoById(Long id);
}//测试代码
public class EnvConfigTest {  private SqlSessionFactory sqlSessionFactory;@Test  public void testAutoMapFull(){  SqlSession session = this.sqlSessionFactory.openSession();  ApplicationRepository mapper = session.getMapper(ApplicationRepository.class);  AppVo e1 = mapper.queryAppVoById(1L);  System.out.println(e1);  }  
}
<mapper namespace="top.sunyog.mybatis.mapper.ApplicationRepository"><resultMap id="appVoMap" type="appVo" autoMapping="true">   <!--注意,这里的association内部没有设置自动映射--><association property="service" column="service_id" foreignColumn="id">  <id column="service_id" property="id"/>  <result column="service_name" property="serviceName"/>  </association>    </resultMap>    <select id="queryAppVoById" resultMap="appVoMap">  select t1.id,t1.app_name,t2.id as service_id,t2.service_name,t2.service_code,t2.service_path from app_test t1  left join service_test t2 on t1.id=t2.app_id  where t1.id=#{id}  </select>
</mapper>

默认配置状态下的打印结果

AppVo{id=1, appName='测试应用1', service=ServiceTestEntity{id=3, serviceName='注册中心', serviceCode='null', servicePath='null', appId=null}}

修改配置为 <setting name="autoMappingBehavior" value="FULL"/>后的结果

AppVo{id=1, appName='测试应用1', service=ServiceTestEntity{id=3, serviceName='注册中心', serviceCode='nacos-service', servicePath='/nacos', appId=null}}

因此,FULL可以实现复杂对象的自动映射

autoMappingUnknownColumnBehavior

备注:自动映射时,发现未知列/属性时的行为。可选值包括NONE、WARNING、FAILING
默认值:NONE
建议值:
建议原因:
选项说明:

配置说明
NONE无操作
WARNING打印警告日志,需要保证org.apache.ibatis.session.AutoMappingUnknownColumnBehavior的日志级别为warn
FAILING抛出 SqlSessionException 异常

测试代码使用上例 autoMappingBehavior中的 testAutoMapFull()方法,修改xml映射文件

<select id="queryAppVoById" resultType="appVo">

默认配置下的输出结果(仅输出打印)

AppVo{id=1, appName='测试应用1', service=null}

配置 <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>后的结果(输出错误日志)

 WARN [main] - Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_id,propertyName=service_id,propertyType=null]WARN [main] - Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_name,propertyName=service_name,propertyType=null]WARN [main] - Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_code,propertyName=service_code,propertyType=null]WARN [main] - Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_path,propertyName=service_path,propertyType=null]
AppVo{id=1, appName='测试应用1', service=null}

配置 <setting name="autoMappingUnknownColumnBehavior" value="FAILING"/>0后的结果(报错退出)

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.session.SqlSessionException: Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_id,propertyName=service_id,propertyType=null]
### The error may exist in mapper/ApplicationMapper.xml
### The error may involve top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById
### The error occurred while handling results
### SQL: select t1.id,t1.app_name,t2.id as service_id,t2.service_name,t2.service_code,t2.service_path         from app_test t1         left join service_test t2 on t1.id=t2.app_id         where t1.id=?
### Cause: org.apache.ibatis.session.SqlSessionException: Unknown column is detected on 'top.sunyog.mybatis.mapper.ApplicationRepository.queryAppVoById' auto-mapping. Mapping parameters are [columnName=service_id,propertyName=service_id,propertyType=null]

lazyLoadingEnabled

备注:延迟加载开关,设置关联查询的延迟加载。其中的关联查询即是通过<association><collection> 标签配置的关联查询
默认值:false(V3.4.1及之前版本为true)
建议值:true
建议原因:很多情况下我们只需要获取主查询中的结果,对关联查询的结果不关心,通过设置延迟加载可以减少不必要的查询。

为了测试这个配置需要修改mapper包的日志级别为 DEBUG

<Loggers>  <Logger name="top.sunyog.mybatis.mapper" level="debug"/>
<Loggers>

测试类

@Test  
public void testLazyLoad(){  SqlSession session = this.sqlSessionFactory.openSession();  SimpleQueryMapper mapper = session.getMapper(SimpleQueryMapper.class);  AppTestEntity entity = mapper.queryAppDetail(2);  System.out.println("主查询结束");  System.out.println("查询结果app_name="+entity.getAppName());System.out.println("获取子查询结果");  DictTest appStatusDict = entity.getAppStatusDict();  System.out.println("子查询结果app_status_dict="+appStatusDict);  
}

默认情况下(或 <setting name="lazyLoadingEnabled" value="false"/>)的输出结果(先完成所有查询,再输出app_name)

DEBUG [main] - ==>  Preparing: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - ====>  Preparing: select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_status' and dict_code=?
DEBUG [main] - ====> Parameters: 0(String)
DEBUG [main] - <====      Total: 1
DEBUG [main] - ====>  Preparing: select * from service_test where app_id=?
DEBUG [main] - ====> Parameters: 2(Integer)
DEBUG [main] - <====      Total: 2
DEBUG [main] - <==      Total: 1
主查询结束
查询结果app_name=公共应用1
获取子查询结果
子查询结果app_status_dict=DictTest{dictName='临时应用', dictCode='0', dictType='app_status', dictSort=0}

配置 <setting name="lazyLoadingEnabled" value="true"/>下的输出(先执行主查询,再打印app_name,再执行后续必要的查询)

DEBUG [main] - ==>  Preparing: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - <==      Total: 1
主查询结束
查询结果app_name=公共应用1
获取子查询结果
DEBUG [main] - ==>  Preparing: select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_status' and dict_code=?
DEBUG [main] - ==> Parameters: 0(String)
DEBUG [main] - <==      Total: 1
子查询结果app_status_dict=DictTest{dictName='临时应用', dictCode='0', dictType='app_status', dictSort=0}

细节:这里需要注意resultMap中设定的 fetchType属性,一个resultMap终端关联关系是否延迟加载取决于fetchType的设置,和整体配置无关。fetchType属性的可选值包括

  1. lazy:延迟加载
  2. eager:非延迟加载

如:可以修改这个resultMap,自定义appStatusDict属性延迟加载 services属性不延迟

<resultMap id="appDetail" type="appTestEntity" autoMapping="true">  ...<association fetchType="lazy" property="appStatusDict" javaType="dictTest" select="queryAppStatus" column="app_status"></association>  <collection fetchType="eager" property="services" column="id" select="queryServices" javaType="ArrayList" ofType="serviceTestEntity"/>  
</resultMap>

细节: 另一个需要注意的是 aggressiveLazyLoading这个配置 👇

aggressiveLazyLoading

备注:开启该配置后,查询结果对象的任意方法调用,都会触发延迟加载属性的加载
默认值:false
建议值:false
建议原因:
任意方法包括getter、setter方法,而getter、setter方法的调用频率极高。而Mybatis自动映射通过setter方法实现,因此开启这个配置后延迟加载也就相当于关闭了(包括fetchType)

开启此配置后,上例的测试代码输出内容直接锁定为

DEBUG [main] - ==>  Preparing: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - ====>  Preparing: select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_status' and dict_code=?
DEBUG [main] - ====> Parameters: 0(String)
DEBUG [main] - <====      Total: 1
DEBUG [main] - ====>  Preparing: select * from service_test where app_id=?
DEBUG [main] - ====> Parameters: 2(Integer)
DEBUG [main] - <====      Total: 2
DEBUG [main] - <==      Total: 1
主查询结束
查询结果app_name=公共应用1
获取子查询结果
子查询结果app_status_dict=DictTest{dictName='临时应用', dictCode='0', dictType='app_status', dictSort=0}

即便设置了fetchType也失效

<resultMap id="appDetail" type="appTestEntity" autoMapping="true"><association fetchType="lazy" property="appStatusDict" javaType="dictTest" select="queryAppStatus" column="app_status"></association>  <collection fetchType="lazy" property="services" column="id" select="queryServices" javaType="ArrayList" ofType="serviceTestEntity"/>
</resultMap>

lazyLoadTriggerMethods

备注:指定对象的哪些方法触发延迟加载,方法名用 ,分隔
默认值:equals,clone,hashCode,toString
建议值:
建议原因:

继续修改方法的内容如下:

public class EnvConfigTest {  private SqlSessionFactory sqlSessionFactory;@Test  public void testLazyLoad(){  SqlSession session = this.sqlSessionFactory.openSession();  SimpleQueryMapper mapper = session.getMapper(SimpleQueryMapper.class);  AppTestEntity entity = mapper.queryAppDetail(2);  System.out.println("主查询结束");  System.out.println("查询结果app_name="+entity.getAppName());  int row = entity.hashCode();  
//        System.out.println("获取子查询结果");  
//        DictTest appStatusDict = entity.getAppStatusDict();  
//        System.out.println("子查询结果app_status_dict="+appStatusDict);  }  
}

默认配置下的输出:(hashCode方法被调用后,执行了所有的延迟加载)

DEBUG [main] - ==>  Preparing: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - <==      Total: 1
主查询结束
查询结果app_name=公共应用1
DEBUG [main] - ==>  Preparing: select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_status' and dict_code=?
DEBUG [main] - ==> Parameters: 0(String)
DEBUG [main] - <==      Total: 1
DEBUG [main] - ==>  Preparing: select * from service_test where app_id=?
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - <==      Total: 2

修改配置 <setting name="lazyLoadTriggerMethods" value="toString"/>后的输出:( hashCode方法调用不再执行延迟加载)

DEBUG [main] - ==>  Preparing: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - <==      Total: 1
主查询结束
查询结果app_name=公共应用1

multipleResultSetsEnabled

备注:是否支持单次查询返回多个结果集,此配置需要数据库驱动的支持。Mysql数据库多结果集查询方法见[[Mybatis结果映射#collection集合类型的多结果集查询]]
默认值:true
建议值:不设置
建议原因:mysql-connector-javaV8数据库驱动中,此项配置无效

useColumnLabel

备注:是否使用列标签代替列名。依赖于数据库驱动
默认值:true
建议值:不设置
建议原因:mysql-connector-java数据库驱动中,此项配置无效
失效原因:
此项设置的区别在于,在对resultSet的处理过程中是调用 ResultSetMetaData#getColumnLabel方法还是 ResultSetMetaData#getColumnName方法,(源码见UnknownTypeHandler#resolveTypeHandlerResultSetWrapper构造方法
而对于mysql-connector-java来说,这两个方法最后都是调用的 Field#getName方法,部分源码如下

package com.mysql.cj.jdbc.result;
public class ResultSetMetaData implements java.sql.ResultSetMetaData {@Override  public String getColumnLabel(int column) throws SQLException {  if (this.useOldAliasBehavior) {  return getColumnName(column);  }  return getField(column).getColumnLabel();  }  @Override  public String getColumnName(int column) throws SQLException {  if (this.useOldAliasBehavior) {  return getField(column).getName();  }  String name = getField(column).getOriginalName();  if (name == null) {  return getField(column).getName();  }  return name;  }protected Field getField(int columnIndex) throws SQLException {  if ((columnIndex < 1) || (columnIndex > this.fields.length)) {  throw SQLError.createSQLException(Messages.getString("ResultSetMetaData.46"), MysqlErrorNumbers.SQL_STATE_INVALID_COLUMN_NUMBER,  this.exceptionInterceptor);  }  return this.fields[columnIndex - 1];  }
}package com.mysql.cj.result;
public class Field implements ProtocolEntity {public String getColumnLabel() {  return getName();  }public String getName() {  return this.columnName.toString();  }
}

useGeneratedKeys

备注:允许 JDBC 自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。
默认值:false
建议值:不设置
建议原因:主键可通过代码自行生成。另外,mysql-connector-javaV8数据库驱动中,此项配置没有任何影响。

细节:简单的主键生成行为可以参考这篇博客,分布式主键生成方案可参考Twitter雪花算法。

mapUnderscoreToCamelCase

备注:是否开启驼峰命名自动映射
默认值:false
建议值:true
建议原因:可以减少 <resultMap>标签的使用

总结

在这篇文章中,我们介绍了关于Mybatis结果映射的配置项,这些配置项大多与 <resultMap>标签相关,可见,在Mybatis中ResultMap是一个重点。其中最常用的就是 mapUnderscoreToCamelCase这个配置,基本属于必开配置。


📩 联系方式
邮箱:qijilaoli@foxmail.com

❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++系列-附录-windows下安装C++环境

C系列-附录-windows下安装C环境 在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 参考 Windows搭建C编程环境(VSCodeMingw-w64) C编译器有哪些 C编译器简介 常见的C编译器 C编译器是将C源代码翻译成可执行程序的工具。以下是一些常见的C编译器&…

How to Develop Word Embeddings in Python with Gensim

https://machinelearningmastery.com/develop-word-embeddings-python-gensim/ 本教程分为 6 个部分;他们是&#xff1a; 词嵌入 Gensim 库 开发 Word2Vec 嵌入 可视化单词嵌入 加载 Google 的 Word2Vec 嵌入 加载斯坦福大学的 GloVe 嵌入 词嵌入 单词嵌入是一种提供单词的…

YOLOv8算法优化:解决YOLOv8无法打印计算量(GFLOPs)的问题点

💡💡💡本文内容:解决YOLOv8无法打印计算量的问题点 💡💡💡本文提供:1)训练阶段自动打印计算量;2)提供离线打印计算量的代码; 1.计算量介绍 FLOPS:注意S是大写,是 “每秒所执行的浮点运算次数”(floating-point operations per second)的缩写。它常被用…

SpringBoot多线程与任务调度总结

一、前言 多线程与任务调度是java开发中必须掌握的技能&#xff0c;在springBoot的开发中&#xff0c;多线程和任务调度变得越来越简单。实现方式可以通过实现ApplicationRunner接口&#xff0c;重新run的方法实现多线程。任务调度则可以使用Scheduled注解 二、使用示例 Slf…

12.28网络流,残留网络,增广路,最大流最小割定理

网络流 概念 是指在一个每条边都有容量的有向图分配流&#xff0c;使一条边的流量不会超过它的容量。通常在运筹学中&#xff0c;有向图称为网络。顶点称为节点而边称为弧。一道流必须匹配一个结点的进出的流量相同的限制&#xff0c;除非这是一个源点──有较多向外的流&…

SAP VA01 创建带wbs号的销售订单包 CJ067的错误

接口错误提示如下 SAP官方 CJ067 124177 - VA01: CJ067 during WBS acct assgmt with a different business area S4的core 刚好能用上 实施 这个note后成功

一个注解实现分布式锁

1、原始写法 我们平常使用redisson的分布式锁是怎么做的&#xff1f; 是不是基本都用的这个模板&#xff0c;既然是模板&#xff0c;那为何不把他抽出来呢&#xff1f; // 尝试加锁&#xff0c;最多等待100秒&#xff0c;上锁以后10秒自动解锁 boolean res lock.tryLock(10…

2023-12-23 组合总和 III和电话号码的字母组合

216. 组合总和 III 思路&#xff1a;使用回溯三部曲&#xff01;① 确认需要传入的参数以及返回值 ② 回溯的终止条件 ③ 单层搜索的逻辑&#xff01;这道题易错点在于单层的逻辑上的遍历起始位置以及回溯回退步骤里要执行的内容&#xff01; class Solution:def combinationSu…

Redis 是如何执行的?

文章目录 命令执行流程步骤一&#xff1a;用户输入一条命令步骤二&#xff1a;客户端先将命令转换成 Redis 协议&#xff0c;然后再通过 socket 连接发送给服务器端步骤三&#xff1a;服务器端接收到命令步骤四&#xff1a;执行前准备步骤五&#xff1a;执行最终命令&#xff0…

docker学习(二十一、network使用示例container、自定义)

文章目录 一、container应用示例1.需要共用同一个端口的服务&#xff0c;不适用container方式2.可用示例3.停掉共享源的容器&#xff0c;其他容器只有本地回环lo地址 总结 二、自定义网络应用示例默认bridge&#xff0c;容器间ip通信默认bridge&#xff0c;容器间服务名不通 自…

关于设计模式、Java基础面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv 设计模式 单例共有几种写法&#xff1f; 细分起来就有9种&#xff1a;懒汉&#x…

常见算法(java版)

冒泡排序 每次从数组中找出最大值放在数组的后面去。 关键步骤 确定总共需要做几轮&#xff1a; 数组的长度-1。 每轮比较几次:数组的长度 - 第i轮。 当前位置大于后一个位置则交换数据。 选择排序 每轮选择当前位置&#xff0c;开始找出后面的较小值与该位置交换。 关键…