解析Mybaits的insert方法返回数字-2147482646的原因

本文探讨了MyBatis配置BATCH执行类型时更新返回值丢失的现象,通过源码分析揭示了返回-2147482646的原因,并对比了SIMPLE配置的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:前几天在做项目demo的时候,发现有一个很奇怪的现象,就是MyBatis发现更新和插入返回值一直为"-2147482646".无论怎么改,这个值一直不变...是在摸不着头脑,百度和谷歌了一下,有这样的说法原来
是由defaultExecutorType设置引起的,如果设置为BATCH,更新返回值就会丢失。
If the BATCH executor is in use, the update counts are being lost.
操作:也就是说在spring的配置文件中,只要把constructor-arg中的executorType改为SIMPLE(以前的值是BATCH就会引发这个问题)或者直接注释掉就可以了
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
        <!-- 执行类型 -->
        <constructor-arg name="executorType" value="SIMPLE"></constructor-arg>
    </bean>

 这么一改果然好使,但是为啥会返回这个奇怪的数字呢?背后有啥原因,本篇博客就来研究一下为什么会返回这个数字,打开我们的idea,又到了跟踪源码的时候了,走起:

1:打开配置文件中的变量,看到SqlSessionTemplate这个类有个构造参数类型ExecutorType了,也就是我们配置的值,当它为BATCH的时候又会怎么样呢?

2:ExecutorType的参数,打开这个类发现它是个枚举类型,也就是说它仅仅只有3种配置的值,SIMPLE、RESUME、BATCH,在配置文件中我们也只能配这三种其中的一个

3:程序执行,可见最终操作的是SqlSession的insert方法,我们就来打开这个方法的源码:

        Reader config = Resources.getResourceAsReader("conf.xml");
        
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(config);
     
        SqlSession sqlSession = sessionFactory.openSession();
    
        String sql = "com.mlxs.mybatis.test.userMapper.insertUser";

        int res= sqlSession.insert(sql, "1");//

4:SqlSession.insert()方法:

public interface SqlSession extends Closeable {
  int insert(String var1);

  int insert(String var1, Object var2);
}

SqlSession是一个接口,里面有insert方法,我们再来看一下这个接口的实现类:

一般在源码中,如果没有特殊配置肯定是采用的Default的设置,我们就来看看DefaultSqlSession的源码:

再找this.insert方法:

可以看到,它调用的是this.update方法,再来找一个update方法:

看到本质上它调用的是executor的update方法,我们再点进去看update方法:

可以看到它是一个接口,那么肯定要找实现类了:

这里就可以看出端倪了,如果没有配置缓存的话,肯定用的是BaseExecutor,那么我们在配置文件中配置的是Batch,毋庸置疑它肯定是选择BatchExecutor这个类中的update方法了:

 

 千呼万唤始出来,这个奇怪的数字原来在这里出来的,其中可以看到它是固定返回的,没有任何判断逻辑...这样就证明了一点,只要你的insert方法在配置文件中配置的是batch,那么它肯定返回这个值!

5:当配置为simple返回的是什么?

根据上面的经验,这里我们直接看SimpleExecutor方法就行了:

接着再看StatementHandler就知道了:

我找到了SimpleStatementHandler的update方法,可以看到它返回是statement.getUpdateCount返回的数字,也就是实际影响的行数,那么就是正常的数值。

 总结:

本篇博客记录了一次源码追踪的过程,从而解释了为什么配置BATCH返回的是这个数字的原因,在实际的编程中,可能会遇到很多奇怪的问题,这时候就要敢于翻源码,答案一定在源码中,才能从根本上知道产生问题的原因。

<think>好的,用户之前问过关于ag-Grid的本地过滤实现,现在他想了解如何用Spring Boot和MyBatis-Plus来封装ag-Grid的过滤功能。我需要先回顾之前的对话,确保这次回答能衔接上。 首先,用户可能已经熟悉了ag-Grid的客户端过滤,现在想结合后端技术实现更复杂的服务端过滤。可能需要将前端的过滤条件传递到后端,由Spring Boot处理,利用MyBatis-Plus进行数据库查询。 需要确定用户的具体需求。是纯服务端过滤,还是混合模式?比如,某些列在前端过滤,某些在服务端。或者整个过滤逻辑都在后端处理,适用于大数据量。 然后,考虑如何将ag-Grid的过滤参数转换成MyBatis-Plus的查询条件。ag-Grid的过滤器可能有不同的类型,比如文本、数字、日期,每种类型对应的过滤条件结构不同,需要解析这些参数并生成对应的SQL条件。 接下来,设计后端的API接口。可能需要接收过滤参数,处理分页、排序等,同时整合MyBatis-Plus的Lambda查询来构建动态SQL。这里要注意分页插件的使用,以及如何将过滤条件转换为QueryWrapper的条件。 另外,用户可能希望知道前后端的数据交互格式,比如如何从ag-Grid的过滤器模型获取参数,并传递给Spring Boot的Controller。需要给出具体的示例代码,比如如何接收过滤参数,并转换为MyBatis-Plus的查询条件。 还要考虑可能的性能问题,比如当数据量很大时,服务端过滤的效率如何优化,可能需要数据库索引的支持,或者分页处理来减少数据传输量。 最后,应该提醒用户注意参数验证和安全性,防止SQL注入,确保过滤参数的合法性。同时,提供一个完整的实现步骤,从前端配置到后端处理,确保用户能够逐步实现功能。 总结,用户需要的是一个整合Spring Boot、MyBatis-Plus和ag-Grid的过滤方案,重点在于参数传递、条件转换和动态查询构建。需要详细讲解每个步骤,并提供代码示例,确保用户能够理解和实施。</think>以下是使用 Spring Boot 与 MyBatis-Plus 封装 ag-Grid 过滤功能的完整实现方案: --- ### 一、技术栈整合原理 ```mermaid sequenceDiagram ag-grid->>前端: 触发过滤事件 前端->>后端: 发送过滤参数(JSON) 后端->>MyBatis-Plus: 动态生成SQL MyBatis-Plus->>数据库: 执行过滤查询 数据库-->>后端: 返回过滤数据 后端-->>前端: 返回分页结果 前端->>ag-grid: 更新渲染数据 ``` --- ### 二、前端封装(ag-Grid 配置) #### 1. 过滤器参数格式 ```javascript // ag-Grid过滤器模型示例 const filterModel = { name: { filterType: 'text', type: 'contains', filter: '张三' }, age: { filterType: 'number', type: 'greaterThan', filter: 25 } }; ``` #### 2. 请求参数封装 ```typescript // 分页+过滤请求DTO interface GridRequest { page: number; pageSize: number; sortModel: SortModel[]; // 排序字段 filterModel: Record<string, any>; // 过滤条件 } ``` --- ### 三、后端核心实现 #### 1. Controller 层 ```java @PostMapping("/data") public PageResult<Employee> getGridData(@RequestBody GridRequest request) { return employeeService.getFilteredData(request); } ``` #### 2. 请求参数对象 ```java @Data public class GridRequest { private Integer page; private Integer pageSize; private List<SortModel> sortModel; private Map<String, Object> filterModel; } @Data public class SortModel { private String colId; // 对应数据库字段 private String sort; // asc/desc } ``` #### 3. Service 实现(核心) ```java public PageResult<Employee> getFilteredData(GridRequest request) { Page<Employee> page = new Page<>(request.getPage(), request.getPageSize()); LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>(); // 动态构建过滤条件 request.getFilterModel().forEach((field, condition) -> { buildCondition(wrapper, field, condition); }); // 处理排序 if (CollectionUtils.isNotEmpty(request.getSortModel())) { request.getSortModel().forEach(sort -> { wrapper.orderBy(true, "asc".equals(sort.getSort()), getColumnName(sort.getColId())); }); } return new PageResult<>(baseMapper.selectPage(page, wrapper)); } // 条件构建工具方法 private void buildCondition(LambdaQueryWrapper<Employee> wrapper, String field, Object condition) { if (condition instanceof Map) { Map<String, Object> filter = (Map<String, Object>) condition; String type = (String) filter.get("type"); Object value = filter.get("filter"); switch (type) { case "contains": wrapper.like(getColumnName(field), value); break; case "equals": wrapper.eq(getColumnName(field), value); break; case "greaterThan": wrapper.gt(getColumnName(field), value); break; // 可扩展其他过滤类型... } } } // 字段名转换(前端字段转数据库列名) private String getColumnName(String field) { // 实现字段映射逻辑,例如驼峰转下划线 return StringUtils.camelToUnderline(field); } ``` --- ### 四、MyBatis-Plus 增强配置 #### 1. 自定义分页结果 ```java @Data public class PageResult<T> { private List<T> data; private Long total; public PageResult(Page<T> page) { this.data = page.getRecords(); this.total = page.getTotal(); } } ``` #### 2. SQL 性能优化 ```yaml # application.yml mybatis-plus: configuration: default-scripting-language: freemarker log-impl: org.apache.ibatis.logging.stdout.StdOutImpl ``` --- ### 五、高级过滤场景处理 #### 1. 复合条件过滤 ```java // 处理 AND/OR 逻辑 if (filter.containsKey("operator")) { String operator = (String) filter.get("operator"); List<Map<String, Object>> conditions = (List<Map<String, Object>>) filter.get("conditions"); if ("AND".equals(operator)) { wrapper.and(qw -> { conditions.forEach(c -> buildCondition(qw, field, c)); }); } else if ("OR".equals(operator)) { wrapper.or(qw -> { conditions.forEach(c -> buildCondition(qw, field, c)); }); } } ``` #### 2. 日期范围过滤 ```java case "inRange": List<String> dates = (List<String>) value; wrapper.between(getColumnName(field), LocalDate.parse(dates.get(0)), LocalDate.parse(dates.get(1))); break; ``` --- ### 六、安全注意事项 1. **字段白名单校验** ```java private static final Set<String> ALLOW_FIELDS = Set.of("name", "age", "department"); // 允许过滤的字段 if (!ALLOW_FIELDS.contains(field)) { throw new IllegalArgumentException("非法过滤字段"); } ``` 2. **SQL注入防护** - 使用 MyBatis-Plus 的 LambdaQueryWrapper - 禁止直接拼接 SQL 语句 - 对输入值进行类型校验 --- ### 七、性能优化建议 1. **索引策略** ```sql CREATE INDEX idx_name ON employee(name); CREATE INDEX idx_age ON employee(age); ``` 2. **分页限制** ```java // 限制最大分页大小 request.setPageSize(Math.min(request.getPageSize(), 1000)); ``` --- ### 八、调试技巧 1. 打印最终 SQL ```java System.out.println(wrapper.getSqlSegment()); // 输出: WHERE name LIKE ? AND age > ? ``` 2. 参数日志 ```java wrapper.getParamNameValuePairs().forEach((k,v) -> System.out.println(k + " => " + v)); ``` --- 通过这种封装方式,可以实现: 1. 前端过滤参数与后端查询的自动映射 2. 动态条件组合的灵活处理 3. 分页与排序的标准实现 4. 安全边界的有效控制 建议根据具体业务需求扩展`buildCondition`方法中的过滤类型处理逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蹉跎之人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值