mybatis-sqlserver批量新增返回id
程序员文章站
2022-05-25 17:06:14
...
遇到的问题
公司最近接到项目需要使用SqlServer,在做SQL兼容的时候遇到问题.批量新增数据时只返回的第一条记录的id
解决思路
- 参考mysql
<insert id="batchInsert" userGeneratedKeys="true" keyProperty="id">
insert into public_user (name,password)
values
<foreach collection="list" separator="," item="item">
(#{item.name}, #{itme.password})
</foreach>
</insert>
具体mybatis封装id的地方在org.apache.ibatis.executor.******.Jdbc3KeyGenerator
主要逻辑是通过Statement.getGeneratedKeys()获取id结果集.
SqlServer只能获取第一个
- 发现上述步骤的Jdbc3KeyGenerator是有接口的KeyGenerator,查看后发现有3个实现类了解到SelectKeyGenerator通过selectKeyt标签可以返回id;
- 查看SelectKeyGenerator源码了解到只支持返回单个id;
- 通过百度了解到SqlServer通过output inserted.id可以输出id;
- 是否可以自己实现KeyGenerator来解决批量返回id的方法呢?
- 最后我没找到配置自定义的实现类的方式,决定通过mybatis的拦截器解决
代码
mybatis拦截器
@Component
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}))
public class SqlServerKeyGeneratorInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 正常执行代码 获取返回结构集
List<Object> values = (List)invocation.proceed();
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
// 判断是否selectKey查询语句
if (ms.getId().endsWith(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {
Configuration configuration = ms.getConfiguration();
// 处理入参对象
Collection<Object> parameters = getParameters(invocation.getArgs()[1]);
// 封装id
for (int i = 0; i < parameters.size(); i++) {
MetaObject metaObject = configuration.newMetaObject(parameters.toArray()[i]);
metaObject.setValue("id", Long.valueOf((Integer)(((Map)values.get(i)).get("id"))));
}
// 返回假数据防止异常
List<Long> ids = new ArrayList<>();
ids.add(1L);
return ids;
}
return values;
}
@Override
public Object plugin(Object target) {
return null;
}
@Override
public void setProperties(Properties properties) {
}
/** 来源 Jdbc3KeyGenerator */
private Collection<Object> getParameters(Object parameter) {
Collection<Object> parameters = null;
if (parameter instanceof Collection) {
parameters = (Collection) parameter;
} else if (parameter instanceof Map) {
Map parameterMap = (Map) parameter;
if (parameterMap.containsKey("collection")) {
parameters = (Collection) parameterMap.get("collection");
} else if (parameterMap.containsKey("list")) {
parameters = (List) parameterMap.get("list");
} else if (parameterMap.containsKey("array")) {
parameters = Arrays.asList((Object[]) parameterMap.get("array"));
}
}
if (parameters == null) {
parameters = new ArrayList<Object>();
parameters.add(parameter);
}
return parameters;
}
}
mapper
<insert id="batchInsert">
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="java.util.Map">
insert into public_user (name,password)
output inserted.id
values
<foreach collection="list" separator="," item="item">
(#{item.name}, #{itme.password})
</foreach>
<selectKey>
</insert>
PS:需要注意的是id对象参数必须放在第一位,拦截器的代码写的比较粗糙,给各位提供思路.有更好方案的可以留言.
上一篇: 爬取twitter数据--使用twint
下一篇: python-根据数据占比来进行随机选择