PostgreSQL+MybatisPlus,设置逻辑删除字段后查询出现:操作符不存在: boolean = integer 错误

项目场景:

Springboot2+PostgreSQL+MybatisPlus


问题描述

在建立Entity时添加了逻辑删除字段:

java 复制代码
@Data
public class BaseEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    // 主键ID
    @TableId
    private String id;

    // 删除标识 (逻辑删除字段)
    @TableLogic
    @TableField(fill = FieldFill.INSERT) // 默认插入时设置为 false
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    private Boolean deleted = false;

    // 创建时间
    @TableField(fill = FieldFill.INSERT) // 插入时自动填充
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    private LocalDateTime createTime;

    // 更新时间
    @TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时自动填充
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    private LocalDateTime updateTime;
}

数据表建立:

sql 复制代码
create table tb_user
(
    id          varchar(255) not null
        primary key,
    username    varchar(255) not null
        unique,
    password    varchar(255) not null,
    deleted     boolean   default false,
    create_time timestamp default CURRENT_TIMESTAMP,
    update_time timestamp default CURRENT_TIMESTAMP
);

查询语句:

java 复制代码
 if (userMapper.selectCount(new QueryWrapper<TbUser>()
                .eq("username", tbUser.getUsername())) > 0) {
            throw new ViewException(ViewExceptionType.DATA_ALREADY_EXISTS, "用户名已存在");
        }

随后在插入数据的时候报错:

复制代码
### Error querying database.  Cause: org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55
### The error may exist in com/sgcchg/data/mapper/UserMapper.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT COUNT( * ) AS total FROM tb_user  WHERE deleted=0     AND (username = ?)
### Cause: org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55
; bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55

org.springframework.jdbc.BadSqlGrammarException: 
### Error querying database.  Cause: org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55
### The error may exist in com/sgcchg/data/mapper/UserMapper.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT COUNT( * ) AS total FROM tb_user  WHERE deleted=0     AND (username = ?)
### Cause: org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55
; bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: 错误: 操作符不存在: boolean = integer
  建议:没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
  位置:55
	at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101) ~[spring-jdbc-5.3.22.jar:5.3.22]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) ~[spring-jdbc-5.3.22.jar:5.3.22]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) ~[spring-jdbc-5.3.22.jar:5.3.22]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) ~[spring-jdbc-5.3.22.jar:5.3.22]
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) ~[mybatis-spring-2.1.2.jar:2.1.2]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439) ~[mybatis-spring-2.1.2.jar:2.1.2]
	at com.sun.proxy.$Proxy98.selectOne(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160) ~[mybatis-spring-2.1.2.jar:2.1.2]
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:87) ~[mybatis-plus-core-3.5.5.jar:3.5.5]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152) ~[mybatis-plus-core-3.5.5.jar:3.5.5]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.5.jar:3.5.5]
	at com.sun.proxy.$Proxy106.selectCount(Unknown Source) ~[na:na]
	at com.sgcchg.business.impl.user.UserServiceImpl.addUser(UserServiceImpl.java:72) ~[classes/:na]

原因分析:

数据库字段是boolean。但是在wrapper查询的时候没有指定deleted,查看报错信息发现最终底层查询会有deleted=0。

原因为:MyBatis-Plus 提供了逻辑删除功能,可以自动在查询条件中添加逻辑删除字段的判断条件。如果 deleted 字段被配置为逻辑删除字段,那么 MyBatis-Plus 在查询时会自动将 deleted = false 这个条件添加到查询语句中。

解决方案:

在 application.yml 或 application.properties中进行以下配置:

bash 复制代码
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted   # 逻辑删除字段名
      logic-not-delete-value: 0     # 表示未删除的值
      logic-delete-value: 1         # 表示已删除的值

bash 复制代码
mybatis-plus.global-config.db-config.logic-delete-field=deleted
mybatis-plus.global-config.db-config.logic-delete-value=true
mybatis-plus.global-config.db-config.logic-not-delete-value=false

即可解决

还有一种方法是修改配置文件:

java 复制代码
@Configuration
public class MybatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 配置逻辑删除
        LogicSqlInjector logicSqlInjector = new LogicSqlInjector();
        interceptor.addInnerInterceptor(logicSqlInjector);
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setObjectWrapperFactory(new DefaultObjectWrapperFactory() {
            @Override
            public boolean hasWrapperFor(Object object) {
                return object instanceof Boolean;
            }

            @Override
            public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
                return new BooleanObjectWrapper(metaObject, (Boolean) object);
            }
        });
    }
}
相关推荐
初次攀爬者15 分钟前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺20 分钟前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
倔强的石头_40 分钟前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
Derek_Smart2 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP3 小时前
MyBatis-mybatis入门与增删改查
java
孟陬6 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌6 小时前
一站式了解四种限流算法
java·后端·go
华仔啊6 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝7 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java