You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用UUIDTypeHandler向PostgreSQL插入UUID失败求助

问题

尝试向PostgreSQL表插入UUID值,自定义了UUIDTypeHandler处理该类型,但插入失败,报错如下:

自定义TypeHandler说明

参考实现了PostgreSQL的UUID类型处理器,用于MyBatis中处理UUID与数据库UUID类型的转换。

XML Mapper代码

<insert id="createUser" parameterType="com.kp.mw.db.dbos.UserDBO">
    INSERT INTO users (id, username, email, birth_year, birth_month, password, creation_time, verification_token, country, language)
    VALUES (#{userId}, #{user.username}, #{user.email}, #{user.birthYear}, #{user.birthMonth}, #{user.password}, #{user.creationTime}, #{user.verificationToken}, #{user.country}, #{user.language})
</insert>

报错信息

middleware_1  | 2022-08-05T00:20:42.113Z <> {thread=http-nio-8080-exec-1} ERROR: [com.kp.mw.exceptions.RestExceptionHandler] com.kp.mw.exceptions.RestExceptionHandlerrlf(Exception occurred:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='userId', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.lang.NullPointerException: Cannot read field "TYPE_CODE" because "jdbcType" is null
middleware_1  |         at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96)
middleware_1  |         at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
middleware_1  |         at jdk.proxy2/jdk.proxy2.$Proxy87.insert(Unknown Source)
middleware_1  |         at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272)
middleware_1  |         at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
middleware_1  |         at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
middleware_1  |         at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
middleware_1  |         at jdk.proxy2/jdk.proxy2.$Proxy89.createUser(Unknown Source)
middleware_1  |         at com.kp.mw.services.UsersService.createUser(UsersService.java:70)
middleware_1  |         at com.kp.mw.controllers.UserController.createUser(UserController.java:57)
middleware_1  |         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
middleware_1  |         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
middleware_1  |         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
middleware_1  |         at java.base/java.lang.reflect.Method.invoke(Method.java:568)
middleware_1  |         at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
middleware_1  |         at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
middleware_1  |         at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
middleware_1  |         at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
middleware_1  |         at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
middleware_1  |         at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
middleware_1  |         at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070)
middleware_1  |         at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
middleware_1  |         at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
middleware_1  |         at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
middleware_1  |         at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
middleware_1  |         at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
middleware_1  |         at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at com.kp.mw.filters.AuthorizationFilter.doFilter(AuthorizationFilter.java:39)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
middleware_1  |         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
middleware_1  |         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
middleware_1  |         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
middleware_1  |         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
middleware_1  |         at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
middleware_1  |         at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
middleware_1  |         at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
middleware_1  |         at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
middleware_1  |         at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
middleware_1  |         at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
middleware_1  |         at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
middleware_1  |         at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
middleware_1  |         at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
middleware_1  |         at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
middleware_1  |         at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)
middleware_1  |         at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
middleware_1  |         at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
middleware_1  |         at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
middleware_1  |         at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
middleware_1  |         at java.base/java.lang.Thread.run(Thread.java:833)
middleware_1  | Caused by: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='userId', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.lang.NullPointerException: Cannot read field "TYPE_CODE" because "jdbcType" is null
middleware_1  |         at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:89)
middleware_1  |         at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:94)
middleware_1  |         at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64)
middleware_1  |         at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:88)
middleware_1  |         at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
middleware_1  |         at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
middleware_1  |         at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
middleware_1  |         at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194)
middleware_1  |         at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181)
middleware_1  |         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
middleware_1  |         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
middleware_1  |         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
middleware_1  |         at java.base/java.lang.reflect.Method.invoke(Method.java:568)
middleware_1  |         at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)
middleware_1  |         ... 61 more
middleware_1  | Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.lang.NullPointerException: Cannot read field "TYPE_CODE" because "jdbcType" is null
middleware_1  |         at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:75)
middleware_1  |         at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87)
middleware_1  |         ... 74 more
middleware_1  | Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.lang.NullPointerException: Cannot read field "TYPE_CODE" because "jdbcType" is null
middleware_1  |         at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:75)
middleware_1  |         at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:67)
middleware_1  |         at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:73)
middleware_1  |         ... 75 more
middleware_1  | Caused by: java.lang.NullPointerException: Cannot read field "TYPE_CODE" because "jdbcType" is null
middleware_1  |         at com.kp.mw.db.typehandlers.UUIDTypeHandler.setNonNullParameter(UUIDTypeHandler.java:20)
middleware_1  |         at com.kp.mw.db.typehandlers.UUIDTypeHandler.setNonNullParameter(UUIDTypeHandler.java:14)
middleware_1  |         at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:73)
middleware_1  |         ... 77 more

解决方案

从报错栈信息可以看出,问题出在UUIDTypeHandler的setNonNullParameter方法中,尝试读取jdbcType.TYPE_CODE但jdbcType为null,结合MyBatis参数映射规则,可通过以下步骤修复:

1. 修正TypeHandler实现,移除对传入jdbcType的依赖

自定义的UUIDTypeHandler应直接指定PostgreSQL的UUID类型,无需依赖外部传入的jdbcType参数:

@Override
public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException {
    // 直接使用PostgreSQL兼容的类型标识
    ps.setObject(i, parameter, java.sql.Types.OTHER);
}

2. 在Mapper中显式指定TypeHandler和jdbcType

在XML Mapper的userId参数上,明确指定类型处理器和jdbcType,确保MyBatis能正确识别并调用自定义处理器:

<insert id="createUser" parameterType="com.kp.mw.db.dbos.UserDBO">
    INSERT INTO users (id, username, email, birth_year, birth_month, password, creation_time, verification_token, country, language)
    VALUES (#{userId, typeHandler=com.kp.mw.db.typehandlers.UUIDTypeHandler, jdbcType=OTHER}, #{user.username}, #{user.email}, #{user.birthYear}, #{user.birthMonth}, #{user.password}, #{user.creationTime}, #{user.verificationToken}, #{user.country}, #{user.language})
</insert>

3. 全局注册TypeHandler(可选)

如果希望所有java.util.UUID类型的参数自动使用该处理器,可在MyBatis配置文件中全局注册:

<typeHandlers>
    <typeHandler handler="com.kp.mw.db.typehandlers.UUIDTypeHandler" javaType="java.util.UUID"/>
</typeHandlers>

Spring Boot环境下也可通过注解实现全局注册:

@Configuration
public class MyBatisConfig {
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.getTypeHandlerRegistry().register(UUID.class, new UUIDTypeHandler());
    }
}

4. 检查参数类型匹配

确保UserDBO中的userId字段类型为java.util.UUID,而非String或其他类型,这样MyBatis才能自动匹配到对应的TypeHandler。


内容的提问来源于stack exchange,提问作者Yonoss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:45:29