使用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
相关产品推荐
相关产品推荐

