*当前使用版本*

Oracle OpenJDK version 17.0.5

mybatis-plus-boot-starter 3.5.2

springboot 2.7.4

问题描述

使用LambdaQueryWrapper查询报错,*Cannot invoke "Object.hashCode()" because "key" is null*

目前解决办法:

  1. 降低JDK版本为1.8
  2. 使用QueryWrapper

测试代码:

Student anita3 = studentMapper.selectOne(new LambdaQueryWrapper<Student>()
                .eq(Student::getNum, 2));

实体:

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("student")
@ApiModel(value="Student对象", description="")
public class Student extends Entity {

    @TableId("id")
    private String id;

    @TableField("name")
    private String name;

    @TableField("num")
    private Integer num;

}

mapper:

public interface StudentMapper extends Mapper<Student> {

}

报错信息:

2022-11-11 15:51:45.047 ERROR 11884 --- [nio-9607-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'ew.sqlSegment != null and ew.sqlSegment != '' and ew.nonEmptyOfWhere'. Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment [java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "key" is null]] with root cause

java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "key" is null
    at java.base/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936) ~[na:na]
    at com.baomidou.mybatisplus.core.toolkit.LambdaUtils.resolve(LambdaUtils.java:62) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.columnToString(AbstractLambdaWrapper.java:63) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.columnToString(AbstractLambdaWrapper.java:59) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.columnToString(AbstractLambdaWrapper.java:39) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.AbstractWrapper.lambda$addCondition$ac69df92$1(AbstractWrapper.java:356) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
    at com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList.childrenSqlSegment(NormalSegmentList.java:92) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.segments.AbstractISegmentList.getSqlSegment(AbstractISegmentList.java:103) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.segments.MergeSegments.getSqlSegment(MergeSegments.java:72) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.conditions.AbstractWrapper.getSqlSegment(AbstractWrapper.java:471) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.apache.ibatis.ognl.OgnlRuntime.invokeMethodInsideSandbox(OgnlRuntime.java:1229) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:1214) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.OgnlRuntime.getMethodValue(OgnlRuntime.java:2092) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ObjectPropertyAccessor.getPossibleProperty(ObjectPropertyAccessor.java:60) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ObjectPropertyAccessor.getProperty(ObjectPropertyAccessor.java:147) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.OgnlRuntime.getProperty(OgnlRuntime.java:3233) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ASTProperty.getValueBody(ASTProperty.java:114) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:141) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:50) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:61) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:560) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:524) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:39) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:297) ~[mybatis-3.5.4.jar:3.5.4]
    at com.baomidou.mybatisplus.core.executor.MybatisCachingExecutor.query(MybatisCachingExecutor.java:88) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.4.jar:3.5.4]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76) ~[mybatis-3.5.4.jar:3.5.4]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.4.jar:2.0.4]
    at jdk.proxy2/jdk.proxy2.$Proxy75.selectOne(Unknown Source) ~[na:na]
    at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:159) ~[mybatis-spring-2.0.4.jar:2.0.4]
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:108) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:96) ~[mybatis-plus-core-3.3.2.jar:3.3.2]
    at jdk.proxy2/jdk.proxy2.$Proxy88.selectOne(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.23.jar:5.3.23]
    at jdk.proxy2/jdk.proxy2.$Proxy89.selectOne(Unknown Source) ~[na:na]
    at com.mpc.anitakit.life.Test.test(Test.java:32) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Comment From: shuaizai88

Entity 代码贴一下

Comment From: Sherry720

Entity

import java.io.Serializable;

public abstract class Entity implements Serializable {
}

StudentMapper

import com.mpc.common.mybatis.entity.Student;
import com.mpc.common.mybatis.base.Mapper;

public interface StudentMapper extends Mapper<Student> {

}

Mapper

package com.mpc.common.mybatis.base;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.mpc.common.model.BizException;
import com.mpc.common.mybatis.DbQuerier;
import com.mpc.common.mybatis.injector.CustomizedMapper;
import com.mpc.common.toolkit.AssertUtil;
import com.mpc.common.toolkit.ReflectUtil;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;


public interface Mapper<T extends Entity> extends CustomizedMapper<T> {
    int DEFAULT_BATCH_SIZE = 20;
    String TABLE_PK_NAME = "id";

    default List<T> selectList() {
        return selectList(Wrappers.emptyWrapper());
    }

    default List<T> selectByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return CollectionUtil.newArrayList();
        }
        return selectBatchIds(idList);
    }

    /**
     * 忽略null值的更新(值为null的字段忽略更新)
     * @param entity
     * @return
     */
    default int updateIgnoredById(T entity) {
        return updateById(entity);
    }

    /**
     * 强制更新(值为null的字段也更新)
     * @param entity
     * @return
     */
    default int updateForcedById(T entity) {
        AssertUtil.isTrue(entity.getClass().isAnnotationPresent(TableName.class), "illegal entity.");
        UpdateWrapper<T> wrapper = new UpdateWrapper<T>();
        ReflectUtil.getFields(entity.getClass()).forEach(field -> {
            try {
                field.setAccessible(true);
                if (field.isAnnotationPresent(TableId.class)) {
                    TableId tableId = field.getAnnotation(TableId.class);
                    wrapper.eq(tableId.value(), field.get(entity));
                } else if (field.isAnnotationPresent(TableField.class)) {
                    TableField tableField = field.getAnnotation(TableField.class);
                    wrapper.set(tableField.value(), field.get(entity));
                }
                field.setAccessible(false);
            } catch (Exception e) {
                throw new BizException(e.getMessage(), e);
            }
        });
        return update(entity, wrapper);
    }

    /**
     * 批量更新
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatchById(List<T> list) {
        return updateBatchById(list, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量更新
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatchById(List<T> list, int batchSize) {
        return batch(list, batchSize, batch -> customizedUpdateBatchById(batch));
    }

    /**
     * 批量插入
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insertBatch(List<T> list) {
        return insertBatch(list, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量插入
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insertBatch(List<T> list, int batchSize) {
        return batch(list, batchSize, batch -> customizedInsertBatch(batch));
    }

    default <R extends SFunction<T, ?>> int increment(Class<T> clazz, Serializable id, R r)  {
        return increment(clazz, id, r, 1);
    }

    /**
     * 并发解决方案:直接采用数据库行锁特性,即sql语句自行+1的方式。
     * --若先取值-计算-赋值,则存在并发问题,比如a取值时b已经取值计算,但是暂未赋值,造成a取值不准确等类似情景
     */
    default <R extends SFunction<T, ?>> int increment(Class<T> clazz, Serializable id, R r, int step)  {
        if (step == 0) {
            return 1;
        }
        String dbColumn = DbQuerier.getDbColumn(clazz, r);
        UpdateWrapper<T> wrapper = new UpdateWrapper();
        wrapper.setSql(dbColumn + " = " + dbColumn + (step > 0 ? " + " : " - ") + Math.abs(step));
        wrapper.eq(TABLE_PK_NAME, id);
        try {
            return update(clazz.newInstance(), wrapper);
        } catch (Exception e) {
            throw new BizException(e.getMessage(), e);
        }
    }

    default <UK extends SFunction<T, ?>> T selectByUk(UK uk, Serializable value) {
        return selectOne(new LambdaQueryWrapper<T>().eq(uk, value));
    }

    default <UK extends SFunction<T, ?>> int updateByUk(T entity, UK uk, Serializable value) {
        return update(entity, new LambdaQueryWrapper<T>().eq(uk, value));
    }

    default <Column extends SFunction<T, ?>> int deleteByColumn(Column column, Serializable value) {
        return delete(new LambdaUpdateWrapper<T>().eq(column, value));
    }

    default <Column extends SFunction<T, ?>> List<T> selectList(Column column, Serializable value, Column... asc) {
        return selectList(new LambdaQueryWrapper<T>().eq(column, value).orderByAsc(asc.length > 0, asc));
    }

    default <Column extends SFunction<T, ?>> int selectCount(Column column, Serializable value) {
        return Optional.ofNullable(selectCount(new LambdaQueryWrapper<T>().eq(column, value))).orElse(0);
    }

    default <C extends SFunction<T, ?>> T selectOneByColumn(Hashtable<C, Serializable> columns) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<T>();
        columns.entrySet().stream().forEach(i -> wrapper.eq(i.getKey(), i.getValue()));
        return selectOne(wrapper);
    }

    default <C extends SFunction<T, ?>, V extends Serializable> T selectOneByColumn(C c1, V v1, C c2, V v2) {
        Hashtable<C, Serializable> sf = new Hashtable<>();
        sf.put(c1, v1);
        sf.put(c2, v2);
        return selectOneByColumn(sf);
    }

    default <C extends SFunction<T, ?>, V extends Serializable> T selectOneByColumn(C c1, V v1, C c2, V v2, C c3, V v3) {
        Hashtable<C, Serializable> sf = new Hashtable<>();
        sf.put(c1, v1);
        sf.put(c2, v2);
        sf.put(c3, v3);
        return selectOneByColumn(sf);
    }

}

CustomizedMapper

package com.mpc.common.mybatis.injector;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.google.common.collect.Lists;
import org.apache.ibatis.annotations.Param;
import org.springframework.cglib.core.internal.Function;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

public interface CustomizedMapper<T> extends BaseMapper<T> {

    /**
     * 自定义批量更新,条件为主键
     * 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
     */
    boolean customizedUpdateBatchById(@Param("list") List<T> list);

    /**
     * 自定义批量插入
     * 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
     */
    boolean customizedInsertBatch(@Param("list") List<T> list);


    /**
     * 批处理工具入口
     * @param list
     * @param batchSize
     * @param func
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean batch(List<T> list, int batchSize, Function<List<T>, Boolean> func) {
        if (CollectionUtil.isEmpty(list)) {
            return true;
        }
        if (batchSize < 1) {
            return false;
        }
        if (list.size() <= batchSize) {
            return func.apply(list);
        }
        Lists.partition(list, batchSize).forEach(batch -> func.apply(Lists.newArrayList(batch)));
        return true;
    }

}

Entity 代码贴一下

Comment From: shuaizai88

伙计,你到底用的3.3.2 还是3.5.2呢。我看你的jar好像是3.3.2,LambdaUtils.resolve 在3.5.2里面已经不存在了,你升级3.5.2测试下呢。

Comment From: Sherry720

伙计,你到底用的3.3.2 还是3.5.2呢。我看你的jar好像是3.3.2,LambdaUtils.resolve 在3.5.2里面已经不存在了,你升级3.5.2测试下呢。

还真是,mybatis-plus-boot-starter是3.5.2,但是mybatis-plus-generator是3.3.2,这两没对上,升级后测试已经可以了。感谢。

Comment From: MYZ6

伙计,你到底用的3.3.2 还是3.5.2呢。我看你的jar好像是3.3.2,LambdaUtils.resolve 在3.5.2里面已经不存在了,你升级3.5.2测试下呢。

厉害,佩服