Too many keys are generated. There are only 1 target objects.
阿新 • • 發佈:2020-12-23
技術標籤:MyBatisSpring Boot
Too many keys are generated. There are only 1 target objects.
記一次由spring boot升級導致的問題解決。
版本資訊:
mybatis-spring-boot-starter : 2.1.4
mybatis-spring: 2.0.6
mybatis : 3.5.6
mysql-connector-java: 8.0.22
錯誤日誌:
Caused by: org.apache.ibatis.executor.ExecutorException: Too many keys are generated. There are only 1 target objects. You either specified a wrong 'keyProperty' or encountered a driver bug like #1523.
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.assignKeysToParam(Jdbc3KeyGenerator.java:121) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.assignKeys(Jdbc3KeyGenerator.java:104) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.processBatch( Jdbc3KeyGenerator.java:85) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.processAfter(Jdbc3KeyGenerator.java:71) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:51) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) ~[mybatis-3.5.5.jar:3.5.5]
at com.jd.eps.eis.product.core.interceptor.TenantInterceptor.intercept(TenantInterceptor.java:80) ~[eis-core-service-2.0.0-SNAPSHOT.jar:?]
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.5.5.jar:3.5.5]
at com.sun.proxy.$Proxy184.update(Unknown Source) ~[?:?]
at com.jd.eps.eis.product.core.interceptor.DataPermissionInterceptor.intercept(DataPermissionInterceptor.java:75) ~[eis-core-service-2.0.0-SNAPSHOT.jar:?]
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.5.5.jar:3.5.5]
at com.sun.proxy.$Proxy184.update(Unknown Source) ~[?:?]
at sun.reflect.GeneratedMethodAccessor277.invoke(Unknown Source) ~[?:?]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_171]
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.5.5.jar:3.5.5]
at com.sun.proxy.$Proxy184.update(Unknown Source) ~[?:?]
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) ~[mybatis-3.5.5.jar:3.5.5]
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) ~[mybatis-3.5.5.jar:3.5.5]
at sun.reflect.GeneratedMethodAccessor416.invoke(Unknown Source) ~[?:?]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_171]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.5.jar:2.0.5]
... 119 more
跟蹤日誌發現是在執行批量插入時,使用了useGeneratedKeys=“true”,因為是批量操作,所以返回多個key,但是在設定的時候發現只有一個物件可以設定,因此報錯。
org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator#processBatch
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
return;
}
try (ResultSet rs = stmt.getGeneratedKeys()) {
final ResultSetMetaData rsmd = rs.getMetaData();
final Configuration configuration = ms.getConfiguration();
if (rsmd.getColumnCount() < keyProperties.length) {
// Error?
} else {
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}
private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
Object parameter) throws SQLException {
if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
// Multi-param or single param with @Param
assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter);
} else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty()
&& ((ArrayList<?>) parameter).get(0) instanceof ParamMap) {
// Multi-param or single param with @Param in batch operation
assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, (ArrayList<ParamMap<?>>) parameter);
} else {
// Single param without @Param
assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
}
}
原因一:
自己開發的Mybatis外掛對parameter型別做了轉換,使原本的MapperMethod.ParamMap型別變成了HashMap型別,導致執行assignKeys方法時走了else的邏輯。
解決方法:
對MapperMethod.ParamMap型別單獨處理。
// 如果引數為空,建立空Map
if (parameterObject == null) {
paramMap = new HashMap<>();
} else if (parameterObject instanceof MapperMethod.ParamMap) {
paramMap = new MapperMethod.ParamMap<>();
paramMap.putAll((Map) parameterObject);
} else if (parameterObject instanceof Map) {
// 解決不可變Map的情況
paramMap = new HashMap<>();
paramMap.putAll((Map) parameterObject);
} else {
// do sth.
}
原因二:
指定keyProperty時應包含list的別名資訊,如keyProperty=“list.id”。
int insertConfigDetails(@Param("list") List<ConfigDetailDO> configDetailDOS);
<insert id="insertConfigDetails" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="list.id">
</insert>