专栏名称: 程序员鱼皮
鹅厂全栈开发,持续分享编程技法和实用项目
目录
相关文章推荐
互联网那些破事  ·  刚刚,阿里巴巴亮出AI王牌! ·  11 小时前  
互联网那些破事  ·  刚刚,阿里巴巴亮出AI王牌! ·  11 小时前  
财联社AI daily  ·  蔡崇信:AI市场规模至少10万亿美元 ·  昨天  
企名片  ·  发现创新先锋 | ... ·  2 天前  
企名片  ·  发现创新先锋 | ... ·  2 天前  
AIGC开放社区  ·  AI紧箍咒!OpenAI发布CoT监控,阻止 ... ·  2 天前  
AIGC开放社区  ·  AI紧箍咒!OpenAI发布CoT监控,阻止 ... ·  2 天前  
雨生云计算  ·  【雨生云计算】独家报道:亚马逊AWS重组AI ... ·  2 天前  
51好读  ›  专栏  ›  程序员鱼皮

MyBatis 批量操作的 5 个坑,千万不要踩了!

程序员鱼皮  · 公众号  · 数据库 科技自媒体  · 2025-02-10 13:30

主要观点总结

本文主要介绍了在使用MyBatis进行批量操作时可能遇到的坑以及相应的解决方案,包括查询条数限制、分页问题、参数数量限制、参数类型和批量条数限制等关键点。

关键观点总结

关键观点1: 查询条数限制

当查询大量数据时,数据库有返回结果集大小的限制,如MySQL的max_allowed_packet和max_execution_time,需考虑分批查询以避免数据丢失。

关键观点2: 分页问题

对于单表大量数据,使用offset进行分页会导致深度分页问题,查询效率低下。可以通过传入起始的staffId来解决。

关键观点3: 参数数量限制

批量插入时,如果参数过多,可能导致数据库报错。如Oracle数据库参数数量超过65535会报错。需对参数数量进行限制。

关键观点4: 参数类型

插入语句中未指定参数类型可能导致插入失败。应给插入语句中的参数指定类型。

关键观点5: 批量条数限制

批量操作旨在减少应用和数据库的交互,提高效率。但不对批量操作如插入、更新做条数限制可能导致操作效率低下或数据库挂起。应对批量条数做限制。


正文

在日常开发中,为了提高操作数据库效率,我们往往会选择批量操作,比如批量插入、批量更新,这样可以减少程序和数据库的交互,减少执行时间。 但是批量操作往往隐藏着一些坑,使用不当,很可能会造成生产事故。

今天来分享使用 MyBatis 批量操作可能会遇到的一些坑。下面我们以一张员工信息表为例进行讲解,建表 SQL 如下(MySQL):

CREATE TABLE `staff` (
  `staff_id` tinyint(3NOT NULL COMMENT '员工编号',
  `name` varchar(20DEFAULT NULL COMMENT '员工姓名',
  `age` tinyint(3DEFAULT NULL COMMENT '年龄',
  `sex` tinyint(1DEFAULT '0' COMMENT '性别,0:男 1:女',
  `address` varchar(300DEFAULT NULL COMMENT '家庭住址',
  `email` varchar(200DEFAULT NULL COMMENT '邮件地址',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`staff_id`)
ENGINE=InnoDB DEFAULT CHARSET=utf8

1.查询条数

<select id="getStaffList" parameterType="int" resultType="Admin">
 select * from staff limit #{offset},50000
select>

对应 Java 代码如下:

public List processStaffList(){
    int offset = 0;
    List staffList = staffDao.getStaffList(offset);
    while(true){
        //...处理逻辑
        if(staffList.size() 50000){
            break;
        }
        offset += 50000;
        staffList = staffDao.getStaffList(offset);
    }
}

上面的查询想一次想查回 50000 条数据,很有可能数据库不能返回 50000 条。一般数据库都有查询结果集限制,比如 MySQL 会受两个参数的限制:

  • max_allowed_packet,返回结果集大小,默认 4M,超过这个大小结果集就会被截断;
  • max_execution_time,一次查询执行时间,默认值是 0 表示没有限制,如果超过这个时间,MySQL 会终止查询,返回结果。

所以,如果结果集太大不能全部返回,而我们在代码中每次传入的 offset 都是基于上次的 offset 加 50000,那必定会漏掉部分数据。

2.分页问题

<select id="getStaffList" resultType="Staff">
 select * from staff limit #{offset},1000
select>

如果单表数据量非常大,offset 会很大造成深度分页问题,查询效率低下。我们可以通过传入一个起始的 staffId 来解决深度分页问题。

我们修改一下 xml 中的代码:

<select id="getStaffList" resultType="Staff">
 select * from staff 
  <if test="staffId != null">
        WHERE staff_id > #{staffId}
  if>
 order by staff_id limit 1000
select>

对应 Java 代码如下:

public List processStaffList(){
    List staffList = staffDao.getStaffList(null);
    while(true){
        //...处理逻辑
        if(staffList.size() 1000){
            break;
        }
        Staff lastStaffInPage = staffList.get(staffList.size() - 1);
        staffList = staffDao.getStaffList(lastStaffInPage.getStaffId());
 }
}

3.参数数量

下面看一下这一条插入 SQL:

"batchInsertStaff">
INSERT INTO staff (`staff_id`, `name`, `age`, `sex`, `address`, `email`) VALUES
 ="staffList" index="" item="item" separator=","






请到「今天看啥」查看全文