mybatis-sqlserver批量新增返回id方式
作者:rong0016
这篇文章主要介绍了mybatis-sqlserver批量新增返回id方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
遇到的问题
公司最近接到项目需要使用SqlServer,在做SQL兼容的时候遇到问题,批量新增数据时只返回的第一条记录的id
解决思路
1.参考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.keygen.Jdbc3KeyGenerator
主要逻辑是通过Statement.getGeneratedKeys()获取id结果集.
SqlServer只能获取第一个
2.发现上述步骤的Jdbc3KeyGenerator是有接口的KeyGenerator,查看后发现有3个实现类了解到SelectKeyGenerator通过selectKeyt标签可以返回id;
3.查看SelectKeyGenerator源码了解到只支持返回单个id;
4.通过百度了解到SqlServer通过output inserted.id可以输出id;
5.是否可以自己实现KeyGenerator来解决批量返回id的方法呢?
6.最后我没找到配置自定义的实现类的方式,决定通过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对象参数必须放在第一位,拦截器的代码写的比较粗糙,给各位提供思路。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。