Mybatis行为配置之Ⅲ—其他行为配置项说明
专栏精选
引入Mybatis
Mybatis的快速入门
Mybatis的增删改查扩展功能说明
mapper映射的参数和结果
Mybatis复杂类型的结果映射
Mybatis基于注解的结果映射
Mybatis枚举类型处理和类型处理器
再谈动态SQL
Mybatis配置入门
Mybatis行为配置之Ⅰ—缓存
Mybatis行为配置之Ⅱ—结果相关配置项说明
文章目录
- 专栏精选
- 引言
- 摘要
- 正文
- defaultExecutorType
- defaultStatementTimeout
- defaultResultSetType
- safeRowBoundsEnabled
- safeResultHandlerEnabled
- jdbcTypeForNull
- defaultScriptingLanguage
- defaultEnumTypeHandler
- callSettersOnNulls
- useActualParamName
- returnInstanceForEmptyRow
- 总结
引言
大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。欢迎来到我的频道,这里汇聚了汇集编程技巧、代码示例和技术教程,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 🙆,期待在这里与你共同度过美好的时光🕹️。今天要和大家分享的内容是Mybatis行为配置之Ⅲ—其他常用配置项说明。做好准备,Let’s go🚎🚀
摘要
在这篇文章中,我们将了解剩下的关于Mybatis行为的配置,在mybatis项目开发过程中这些配置可能并不常用,而且大多数情况下都是使用默认配置,了解这些配置的意义可以让我们在解决很多罕见异常问题时有的放矢,不至于手忙脚乱。那么准备好开启今天的神奇之旅了吗?
正文
今天我们介绍Mybatis中最后几个控制Mybatis行为的配置项,它们是
defaultExecutorType
备注:配置默认的执行器。
默认值:SIMPLE
可选值:
值 | 说明 | 对应的Executor实现类 |
---|---|---|
SIMPLE | 普通的执行器,使用JDBC默认Statement | SimpleExecutor |
REUSE | 预处理语句执行器,使用JDBC的PreparedStatement | ReuseExecutor |
BATCH | 重用语句+批量更新执行器 | BatchExecutor |
建议值:SIMPLE
建议原因:SIMPLE比较通用。如果有特殊需求,可以通过 SqlSessionFactoryBuilder#openSession(ExecutorType execType)
方法获取到包含对应的Executor的SqlSession。
注:Executor
保存在 org.apache.ibatis.session.defaults.DefaultSqlSession
类中。
批量插入数据的代码示例
public class EnvConfigTest { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Test public void testBatchInsert(){ List<AppTestEntity> list=new ArrayList<>(); AppTestEntityBuilder builder = new AppTestEntityBuilder(); builder.setAppName("test-name").setAppCode("test-name-code").setAuthType("1").setCreator("junit"); list.add(builder.build()); //省略n个list.add //关键在ExecutorType.BATCH SqlSession session = this.sqlSessionFactory.openSession(ExecutorType.BATCH); ApplicationRepository mapper = session.getMapper(ApplicationRepository.class); list.stream().forEach(o->{ mapper.addApp(o); }); session.commit(); session.close(); } }
defaultStatementTimeout
备注:等待数据库响应的秒数。这项配置需要数据库驱动的支持,在Mysql中此项配置基本无效,在postgres数据库中此配置有效
默认值:null
可选值:任意正整数
建议值:根据实际情况设置
建议原因:取决于数据库硬件和配置
Postgres配置下的测试代码:
public class PostgresTest { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Before public void before(){ try (InputStream inputStream = PostgresTest.class.getResourceAsStream("/mybatis-config.xml")){ this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream,"postgres9"); this.sqlSession=this.sqlSessionFactory.openSession(); } catch (IOException e) { throw new RuntimeException(e); } } @After public void after(){ this.sqlSession.clearCache(); this.sqlSession.close(); } //新增十万条数据@Test public void testBatchInsert(){ List<AppTestEntity> list=new ArrayList<>(); AppTestEntityBuilder builder = new AppTestEntityBuilder(); builder.setAppName("test-name").setAppCode("test-name-code").setAuthType("1").setCreator("junit"); for (int i = 0; i < 100000; i++) { AppTestEntity e = builder.build(); e.setId(((long) i+1)); list.add(e); } //省略n个list.add SqlSession session = this.sqlSessionFactory.openSession(ExecutorType.BATCH); ApplicationRepository mapper = session.getMapper(ApplicationRepository.class); list.stream().forEach(o->{ mapper.addApp(o); }); session.commit(); session.close(); } //查询测试@Test public void testFetchSize(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); long start = System.currentTimeMillis(); List<AppTestEntity> list = mapper.queryList("1"); long gap = System.currentTimeMillis() - start; System.out.println("selected result size: "+list.size()); System.out.println("selected time: "+gap); }
}
配置 <setting name="defaultFetchSize" value="1"/>
后的输出
selected result size: 100000
selected time: 8994
配置 <setting name="defaultFetchSize" value="1000"/>
后的输出
selected result size: 100000
selected time: 413
不配置情况下的输出
selected result size: 100000
selected time: 418
细节 这里需要注意,此配置会被 fetchSize
属性覆盖。fetchSize可以通过以下方式设置
- 注解的方式
@Select(value = "select * from app_test where auth_type=#{type}")
@Options(fetchSize = 1000)
List<AppTestEntity> queryList(@Param("type") String type);
- 标签的方式
<select id="queryList" resultType="AppTestEntity" fetchSize="1000"> select * from app_test where auth_type=#{type}
</select>
defaultResultSetType
备注:指定语句默认的滚动策略
可选值:
配置值 | 说明 |
---|---|
FORWARD_ONLY | 索引只能向后方滚动,不能往前 |
SCROLL_SENSITIVE | 索引可向前后滚动,且更新敏感 |
SCROLL_INSENSITIVE | 索引可向前后滚动,且更新不敏感 |
DEFAULT | 默认,效果和不设置相同 |
默认值:null(DEFAULT)
建议值:不设置
建议原因:不常用,此配置是对jdbc的行为控制,而在mybatis项目中不会直接操作jdbc
safeRowBoundsEnabled
备注:是否允许在嵌套语句(子查询)中使用分页API(RowBounds)。如果允许使用则设置为 false
默认值:false
建议值:
建议原因:
此配置常见的生效情况是,调用了 sqlSession#selectList(String statement,Object param,RowBounds rowBounds)
这个方法,而参数statement
又是嵌套语句,如以下测试代码:
@Test
public void testSafeRow(){ List objects = this.sqlSession.selectList("top.sunyog.mybatis.mapper.SimpleQueryMapper.queryAppDetail", 1, new RowBounds(0, 1)); for (Object obj : objects) { System.out.println(obj); }
}
此代码在默认配置情况下可以正常输出
AppTestEntity{id=null, appName='测试应用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='3', authTypeDict=DictTest{dictName='NONE', dictCode='1', dictType='app_auth_type', dictSort=0}, appStatusDict=DictTest{dictName='正常应用', dictCode='3', dictType='app_status', dictSort=0}, services=[ServiceTestEntity{id=3, serviceName='注册中心', serviceCode='nacos-service', servicePath='/nacos', appId=1}]}
而配置 <setting name="safeRowBoundsEnabled" value="true"/>
后,会报错
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.executor.ExecutorException: Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. Use safeRowBoundsEnabled=false setting to bypass this check.
### The error may exist in mapper/SimpleQueryMapper.xml
### The error may involve top.sunyog.mybatis.mapper.SimpleQueryMapper.queryAppDetail
### The error occurred while handling results
### SQL: 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
### Cause: org.apache.ibatis.executor.ExecutorException: Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. Use safeRowBoundsEnabled=false setting to bypass this check.
safeResultHandlerEnabled
备注:是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false
默认值:true
建议值:按实际情况设置
建议原因:
结果处理器ResultHandler的使用方法见Mybatis基于注解的结果映射这篇文章
jdbcTypeForNull
备注:当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER
可选值:org.apache.ibatis.type.JdbcType
常量
默认值:OTHER
建议值:不设置
建议原因:
defaultScriptingLanguage
备注:指定动态 SQL 生成使用的默认脚本语言。
默认值:org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
建议值:不设置
建议原因:不常用
defaultEnumTypeHandler
备注:指定枚举类型的默认TypeHandler
,关于枚举类型的TypeHandler使用示例,见[[Mybatis基础#枚举类型映射]]
默认值:EnumTypeHandler
建议值:按实际情况设置,建议设置为 EnumOrdinalTypeHandler
建议原因:实际应用中,枚举类型大多数都是顺序编码的字典值
callSettersOnNulls
备注:指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法
默认值:false
建议值:true
建议原因:返回值中某个字段为null时,再map对象中也会插入这个对应的key,这样可以减少对map的 containsKey
方法操作。
通过以下代码测试设置的行为
@Test
public void testNullSet(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); //在这之前先执行这个sql//update app_test set creator=null where id=13;List<Map<String, Object>> list = mapper.queryMapRes(13); System.out.println(list);
}
默认设置时的输出:
[{app_name=test-name, auth_type=1, id=13, create_date=2023-11-30, app_code=test-name-code}]
配置 <setting name="callSettersOnNulls" value="true"/>
时的输出
[{app_name=test-name, auth_type=1, creator=null, id=13, create_date=2023-11-30, app_code=test-name-code}]
useActualParamName
备注:允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,项目必须采用 Java 8 编译,并且加上 -parameters 选项
默认值:true
建议值:true
建议原因:
parameters选项的添加方式为修改maven的pom.xml
文件
细节:这个插件安装或修改后,需要执行maven:clean
和maven:compile
后才能生效
<project>
...<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
</project>
新增测试代码
@Test
public void testMethodParam(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); List<AppTestEntity> list = mapper.getAppByStatusAndAuthType("3","1"); System.out.println(list);
}
public interface SimpleQueryMapper {//注意,这里的入参没有添加@Param注解List<AppTestEntity> getAppByStatusAndAuthType(String status,String authType);
}
<select id="getAppByStatusAndAuthType" resultType="appTestEntity"> <include refid="top.sunyog.mybatis.mapper.ApplicationRepository.query_column"></include> where app_status=#{status} and auth_type=#{authType}
</select>
配置 <setting name="useActualParamName" value="false"/>
后执行报错
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'status' not found. Available parameters are [0, 1, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'status' not found. Available parameters are [0, 1, param1, param2]
默认配置或 <setting name="useActualParamName" value="true"/>
配置下,打印结果
[AppTestEntity{id=1, appName='测试应用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='3', authTypeDict=null, appStatusDict=null, services=null}]
returnInstanceForEmptyRow
备注:当返回行的所有列都是空时,默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集
默认值:false
建议值:true
建议原因:可减少空指针验证
测试代码
public interface SimpleQueryMapper {@Select("select name,code from empty_table_test where 1=1 limit 0,1") Map<String, Object> queryEmptyMap(int i);
}public class EnvConfigTest {@Test public void testReturnEmptyObj(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); Map<String,Object> entity = mapper.queryEmptyMap(112); System.out.println(entity); }
}
新增可为空的测试表
create table empty_table_test
( name int null, code varchar(32) null
);
insert into empty_table_test(name,code) values(null,null),(null,null)
默认配置下的输出
null
配置 <setting name="returnInstanceForEmptyRow" value="true"/>
时的输出
{}
总结
今天介绍的配置项在日常工作中很多都不是很常用,但了解这些配置可以减少很多不必要的错误,甚至解决一些罕见的异常问题。如 returnInstanceForEmptyRow
这个配置能在很大程度上减少空指针异常的出现。
📩 联系方式
邮箱:qijilaoli@foxmail.com❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页
相关文章:

Mybatis行为配置之Ⅲ—其他行为配置项说明
专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…...
高并发系统常见问题及解决方案(Java)
在 Java Web 应用中,高并发环境会带来一系列的挑战,这些挑战可能会影响应用的性能、稳定性和可用性。下面是一些常见的问题以及相应的解决方案: 1. 线程资源竞争 问题: 当多个线程尝试同时访问同一资源时,可能会导致竞争条件,进而影响数据的完整性。 解决方案: 使用同步…...

【鸿蒙千帆起】《钢岚》成为首款基于 HarmonyOS NEXT 开发的战棋新游
近日,紫龙游戏旗下 BlackJack 工作室全新战棋旗舰作品《钢岚》在华为游戏中心首发上线,并宣布《钢岚》完成鸿蒙原生应用开发,成为基于 HarmonyOS NEXT 开发的首款战棋新游,不但进一步丰富了鸿蒙生态战棋品类游戏内容,也…...
【QT】qt各模块描述
【未完待续】 QT主要版本,各个模块的作用描述。 QT5.12 版本(只有部分) qtgamepad: 提供了对游戏手柄的支持。qtandroidextras: 提供了一些特定于Android的功能。qtmacextras: 提供了一些特定于macOS的功能。qtx11extras: 提供了一些特定于X11的功能。qtsensors:…...

Go 泛型之明确使用时机与泛型实现原理
Go 泛型之明确使用时机与泛型实现原理 文章目录 Go 泛型之明确使用时机与泛型实现原理一、引入二、何时适合使用泛型?场景一:编写通用数据结构时场景二:函数操作的是 Go 原生的容器类型时场景三:不同类型实现一些方法的逻辑相同时…...

web3方向产品调研
每次互联网形态的改变,都会对世界产生很大的影响,上一次对社会产生重大影响的互联网形态(Web2.0)催生了一批改变人类生活和信息交互方式的企业。 目录 概述DAO是什么?为什么我们需要DAO? 金融服务金融桥接及周边服务D…...

【计算机视觉】角点检测(Harris、SIFT)
Harris 角点指的是窗口延任意方向移动,都有很大变化量的点。 用数学公式表示为: E(u,v)反映的移动后窗口的差异,w(x,y)为每个像素的点权值,I(xu,yv)是移动的像素值,I(x,y)是移动前的像素值。 将E(u,v)进行泰勒展开&am…...

Python实现张万森下雪了的效果
系列文章 序号文章目录直达链接表白系列1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心http…...
最长的指定瑕疵度的元音子串 (100%用例)C卷 (JavaPythonNode.jsC语言C++)
开头和结尾都是元音字母(aeiouAEIOU)的字符串为 元音字符串 ,其中混杂的非元音字母数量为其 瑕疵度 。比如 : “ a ” 、 “ aa ”是元音字符串,其瑕疵度都为 0 “ aiur ”不是元音字符串(结尾不是元音字符) “ abira ”是元音字符串,其瑕…...

Qt/C++音视频开发62-电子放大/按下选择区域放大显示/任意选取区域放大
一、前言 电子放大这个功能思考了很久,也是一直拖到近期才静下心来完整这个小功能,这个功能的前提,主要得益于之前把滤镜打通了,玩出花样来了,只要传入对应的滤镜字符串,就可以实现各种各样的效果…...

Vue(一):Vue 入门与 Vue 指令
Vue 01. Vue 快速上手 1.1 Vue 的基本概念 用于 构建用户界面 的 渐进性 框架 构建用户界面:基于数据去渲染用户看到的界面渐进式:不需要学习全部的语法就能完成一些功能,学习是循序渐进的框架:一套完整的项目解决方案&#x…...

C语言——最古老的树
归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言📝 缺乏明确的目标,一生将庸庸…...

dnSpy调试工具断点信息是保存在哪里的呢
本人是C#开发,dnSpy工具用的比较多,有时候想把有用的断点信息保留下来,挪到别的机器上也能使用。我做这个事情的主要目标是在调试我们公司的程序时,顺带把访问的sql也进行输出,就可以偷懒不用每次都去查阅代码了&#…...

融汇贯通 —— 2023年技术与心灵的双重成长旅程
当我们站在2023年的岁末,回望这一年赋予我们的经历和挑战,心中涌动的感慨与启示像朝日初升的光芒,照亮脚下的路,亦照见心中的路。在此,我想分享几个方面的感悟和成长,愿它们能有所触动,成为您前…...

基于element ui封装table组件
效果图: 1.封装表格代码如下 <template> <div><div class"TableList"><el-tablev-loading"loading"selection-change"selectionChange"class"table":data"tableData":border"hasBorde…...

MySQL进阶之(一)逻辑架构
一、逻辑架构 1.1 逻辑架构剖析1.1.1 连接层1.1.2 服务层01、基础服务组件02、SQL Interface:SQL 接口03、Parser:解析器04、Optimizer:查询优化器05、Caches & Buffers: 查询缓存组件 1.1.3 引擎层1.1.4 存储层1.1.5 总结 1.…...

【前端学习指南】开启 Vue 的学习之旅
🍭 Hello,我是爱吃糖的范同学 秋招终于结束了(拿到了比较满意的 offer🎉🎉🎉,后续也会有“面筋”系类给大家分享),目前我终于也有足够的时间和精力来完成我 23 年遗留下…...
编程笔记 html5cssjs 011 HTML页面划分
编程笔记 html5&css&js 011 HTML页面划分 HTML的框架、区块和布局是什么,它们之前的关系是怎样的?框架注意 接下来要看一下网页内的划分。通过框架、区块及布局等方式,将网页从一个长方形整体划分为若干个部分,以合理展示…...

Centos7:Jenkins+gitlab+node项目启动(2)
Centos7:Jenkinsgitlabnode项目启动(1) Centos7:Jenkinsgitlabnode项目启动(1)-CSDN博客 Centos7:Jenkinsgitlabnode项目启动(2) Centos7:Jenkinsgitlabnode项目启动(2)-CSDN博客 Centos7:Jenkinsgitlabnode项目启…...

Qt+Opencv:人脸检测
话接上一篇,我们仍使用在上篇《QtOpencv:Qt中部署opencv》创建的Qt项目来测试opencv提供的sample。 在正式开始本篇之前,我们先说做一下准备工作: 一、opencv官方文档 学习最权威和最可靠的方式,就是阅读官方文档和…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...