Too many keys are generated. There are only 1 target objects.

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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值