项目场景:

mybatis insert 过后返回 sys_guid() 生成的主键


问题描述:

一开始 mapper 这样写的:

String addReturnId(Storehouse storehouse);

对应的 xml 是这样的:

<insert id="addReturnId" parameterType="com.erow.ddzy.bizc.domain.bizc.Storehouse">
<selectKey keyProperty="storehouseId" order="BEFORE" resultType="String">
select sys_guid() from dual
</selectKey>
insert into ddzy_storehouse(
storehouse_id,
<if test="storehouseName != null and storehouseName != ''">storehouse_name,</if>
<if test="orgId != null and orgId != ''">org_id,</if>
<if test="orgName != null and orgName != ''">org_name,</if>
<if test="buildType != null and buildType != ''">build_type,</if>
<if test="length != null ">length,</if>
<if test="width != null ">width,</if>
<if test="height != null ">height,</if>
<if test="area != null ">area,</if>
last_update_date
)values(
#{storehouseId},
<if test="storehouseName != null and storehouseName != ''">#{storehouseName},</if>
<if test="orgId != null and orgId != ''">#{orgId},</if>
<if test="orgName != null and orgName != ''">#{orgName},</if>
<if test="buildType != null and buildType != ''">#{buildType},</if>
<if test="length != null ">#{length},</if>
<if test="width != null ">#{width},</if>
<if test="height != null ">#{height},</if>
<if test="area != null ">#{area},</if>
sysdate
)
</insert>

然后启动测试就报错:

has an unsupported return type: class java.lang.String


原因分析:

mybatis insert 后返回 uuid 的主键不是这样写的,查看源码 insert 对应的 mapper 方法返回值只能是 int、long、boolean ,没有字符串。

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}

if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
private Object rowCountResult(int rowCount) {
Object result;
if (this.method.returnsVoid()) {
result = null;
} else if (!Integer.class.equals(this.method.getReturnType()) && !Integer.TYPE.equals(this.method.getReturnType())) {
if (!Long.class.equals(this.method.getReturnType()) && !Long.TYPE.equals(this.method.getReturnType())) {
if (!Boolean.class.equals(this.method.getReturnType()) && !Boolean.TYPE.equals(this.method.getReturnType())) {
throw new BindingException("Mapper method '" + this.command.getName() + "' has an unsupported return type: " + this.method.getReturnType());
}

result = rowCount > 0;
} else {
result = (long)rowCount;
}
} else {
result = rowCount;
}

return result;
}

解决方案:

对应的 mapper 返回值还是改为 int:

int addReturnId(Storehouse storehouse);

返回的 String 类型的主键,直接从传入的对象 storehouse 里的 get 方法取:

int rows = storehouseService.insertReturnId(storehouse);
String storehouseId = storehouse.getStorehouseId();