问题描述: 在使用mybatis对数据库执行更新操作时,parameterType为某个具体的bean,而bean中传入的参数为null时,抛出异常如下:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property=‘pxh‘, mode=IN, javaType=class java.lang.Long, jdbcType=null, numericScale=null, resultMapId=‘null‘, jdbcTypeName=‘null‘, expression=‘null‘}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #5 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型: 1111

问题描述:

在使用mybatis对数据库执行更新操作时,parameterType为某个具体的bean,而bean中传入的参数为null时,抛出异常如上:




mapper文件中代码如下:

<update id="update" parameterType="com.hsoft.mss.xtgl.model.Bean">
        update table
        <set>
                pxh  = #{pxh},    // 当pxh传入null时,抛出上述异常,pxh在bean中的类型为Long
                time = sysdate
        </set>
        where id = #{id}
</update>

 

解决办法一:

经过对代码分析,是由于未指定传入参数pxh的类型,当mybatis接收到null时,无法将其正确的进行解析,进而导致上述异常。

将mapper中代码修改如下:

<update id="update" parameterType="com.hsoft.mss.xtgl.model.Bean">
        update table
        <set>
                pxh  = #{pxh,jdbcType=NUMERIC}, //将pxh的类型指定为NUMERIC即可
                time = sysdate
        </set>
        where id = #{id,jdbcType=VARCHAR}
</update>

解决办法二:

在配置文件mybatis-config.xml中加入如下代码:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
       ... 
    <settings>
        <setting name="jdbcTypeForNull" value="NULL" />
    </settings>
       ... 
</configuration>

 

这样,即使传入参数为null,mybatis也能够将其转换成正确的数据类型,并进行存储操作。

 

附:常见的Jdbc Type 与 Java Type之间的关系

JDBC Type            Java Type  
CHAR                 String  
VARCHAR              String  
LONGVARCHAR          String  
NUMERIC              java.math.BigDecimal  
DECIMAL              java.math.BigDecimal  
BIT                  boolean  
BOOLEAN              boolean  
TINYINT              byte  
SMALLINT             short  
INTEGER              int  
BIGINT               long  
REAL                 float  
FLOAT                double  
DOUBLE               double  
BINARY               byte[]  
VARBINARY            byte[]  
LONGVARBINARY        byte[]  
DATE                 java.sql.Date  
TIME                 java.sql.Time  
TIMESTAMP            java.sql.Timestamp  
CLOB                 Clob  
BLOB                 Blob  
ARRAY                Array
<think>好的,我现在需要帮助用户解决在MyBatis Plus中判断传入参数是否为空的最佳实践。首先,我需要回顾用户的问题和之前的对话历史。用户之前询问了如何区分两个List<Map<String, Object>>中的相同值和不同值,我给出了使用HashSet和自定义比较的方法,还提到了处理复杂类型和序列化的方案。现在用户的新问题是关于MyBatis Plus中参数是否为空的判断。 用户提供的引用内容中提到了MyBatis Plus的配置、测试用例、批量删除以及自定义异常接口。其中,引用[1]展示了如何配置MybatisPlusInterceptor,引用[3]是测试用例,引用[4]讨论了批量操作和BatchExecutor,引用[5]涉及自定义异常。这些可能和参数判断有关联吗?比如,在配置拦截器可能需要处理参数,或者在批量操作中需要检查参数是否为空以避免错误。 用户的需求是判断传入参数是否为空的最佳实践。首先,我需要回忆MyBatis Plus的条件构造器QueryWrapper和UpdateWrapper,它们通常用于构建查询条件,其中可以判断字段是否为空。例如,使用isNull和isNotNull方法。此外,MyBatis Plus的注解@TableField可能也有策略来处理空值,比如在插入或更新自动忽略空字段。 另外,用户可能在XML映射文件中使用动态SQL标签,如<if>,来根据参数是否为空决定是否包含某段SQL。例如,在update操作中,只更新非空的字段,避免将数据库中的现有值覆盖为null。同,引用[4]中提到的批量删除和动态SQL拼接可能涉及参数非空判断,以防止SQL语句过大或参数为空导致的错误。 还需要考虑自定义注解或拦截器的可能性。例如,通过自定义拦截器在SQL执行前检查参数,如果必填参数为空则抛出异常。引用[5]中的自定义异常接口BaseErrorInfoInterface可能在这里派上用场,可以定义参数为空的错误码和描述。 同,全局配置中的jdbcTypeForNull设置也很重要,当字段值为nullMyBatis会如何处理。默认情况下,可能会转换为OTHER类型,但有些数据库不支持,需要明确指定为NULL。 此外,用户可能希望在不同操作(插入、更新、查询)中有不同的空值处理策略。例如,插入忽略null字段,更新同样忽略,而查询可能需要将空参数作为查询条件的一部分。 需要综合这些方法,给出几种最佳实践,并说明适用场景。例如,使用条件构造器在服务层进行判断,或者在XML中使用动态SQL,或者利用注解配置策略。还要考虑代码的简洁性、维护性和性能影响。 最后,确保回答结构清晰,分步骤说明,并提供代码示例,如使用QueryWrapper的示例、XML中的<if>标签示例,以及全局配置的示例。同,提醒用户注意jdbcTypeForNull的配置,避免数据库兼容性问题,并建议结合自定义异常处理参数为空的情况,提升系统健壮性。</think>### MyBatis Plus 判断参数为空的最佳实践 在 MyBatis Plus 中判断参数是否为空可以通过以下方案实现,根据不同的场景选择合适的方法: --- #### 1. **使用条件构造器 `QueryWrapper/UpdateWrapper` 的链式方法** 适用于**动态构建查询条件**或**更新操作**过滤空值。 ```java // 示例:查询 name 不为空且 age 大于 18 的记录 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper .eq(StringUtils.isNotBlank(name), "name", name) // 仅当 name 非空生效 .gt(age != null, "age", age); List<User> users = userMapper.selectList(queryWrapper); ``` - **`eq(condition, column, value)`**:当 `condition=true` 添加条件 - **优势**:链式语法简洁,支持空值过滤和复杂逻辑组合[^1] --- #### 2. **XML 映射文件中使用动态 SQL 标签** 适用于**复杂 SQL 逻辑**或需要**复用 SQL 片段**的场景。 ```xml <!-- 示例:根据参数动态更新非空字段 --> <update id="updateUser" parameterType="User"> UPDATE user <set> <if test="name != null and name != &#39;&#39;">name = #{name},</if> <if test="age != null">age = #{age},</if> </set> WHERE id = #{id} </update> ``` - **`<if>` 标签**:通过 OGNL 表达式判断参数是否为空 - **注意**:避免 SQL 注入,优先使用 `#{}` 占位符[^2] --- #### 3. **全局配置空值处理策略** 通过 MyBatis Plus 的全局配置,控制**插入/更新操作中空值的处理方式**: ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加空值处理策略(需自定义拦截器或使用已有策略) return interceptor; } } ``` - **字段策略注解**:在实体类字段上使用 `@TableField` ```java public class User { @TableField(insertStrategy = FieldStrategy.NOT_EMPTY) private String name; // 插入仅当 name 非空才包含该字段 } ``` - **策略选项**: - `FieldStrategy.NOT_NULL`:非 null 更新 - `FieldStrategy.NOT_EMPTY`:非空(如 String 类型还需非空字符串)[^3] --- #### 4. **自定义注解或拦截器校验参数** 适用于**强制校验必填参数**的业务场景: ```java // 自定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface RequiredParam { } // AOP 拦截器 @Aspect @Component public class ParamCheckAspect { @Before("@annotation(requiredParam)") public void checkParam(JoinPoint joinPoint, RequiredParam requiredParam) { Object[] args = joinPoint.getArgs(); for (Object arg : args) { if (arg == null || (arg instanceof String && ((String) arg).isEmpty())) { throw new BusinessException("参数不能为空"); // 引用自定义异常接口[^5] } } } } ``` --- #### 5. **处理 JDBC 类型与空值兼容性** 在 `application.yml` 中配置 `jdbcTypeForNull`,避免数据库驱动不兼容: ```yaml mybatis: configuration: jdbc-type-for-null: null # 明确指定 null 值的 JDBC 类型 ``` --- ### 方案对比 | 方法 | 适用场景 | 优点 | 缺点 | |---------------------|----------------------------|--------------------------|-----------------------| | 条件构造器 | 简单查询/更新 | 代码简洁,链式调用 | 复杂 SQL 支持有限 | | XML 动态 SQL | 复杂业务逻辑 | 灵活,支持复用 SQL 片段 | 需维护 XML 文件 | | 全局字段策略 | 统一控制空值行为 | 配置简单,减少重复代码 | 无法覆盖所有特殊场景 | | 自定义校验 | 强制参数校验 | 业务逻辑与数据层解耦 | 增加代码复杂度 | --- ### 推荐实践 1. **优先使用条件构造器**处理简单空值逻辑(如查询过滤) 2. **复杂业务逻辑**使用 XML 动态 SQL 标签(如多表关联更新) 3. **关键参数**通过自定义注解+AOP拦截器强制校验(如支付接口的金额字段)[^5] 4. 全局配置 `jdbcTypeForNull` 避免数据库兼容性问题[^4] --- ### 示例代码 ```java // 使用条件构造器实现动态更新 public void updateUserIfNotNull(User user) { UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper .set(user.getName() != null, "name", user.getName()) .set(user.getAge() != null, "age", user.getAge()) .eq("id", user.getId()); userMapper.update(null, updateWrapper); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值