需求
借助mybatis 的provider实现一个比较通用的,批量插入数据接口。
Mapper接口
第一参数为需要批量插入的数据,第二个参数为对应实体类的class
public interface BaseDao<T> {
@InsertProvider(type = BaseProvider.class, method = "batchInsert")
int batchInsert(@Param("lists") List<T>lists, Class<T>clazz);
}
Provider
工具类代码未贴。
主要是获取表名、获取数据库字段相关的类。
public <T> String batchInsert(List<T>lists, Class<T> clazz) {
String tableName = getTableName(clazz);
List<Field>declaredFields = getSupperDeclaredFields(clazz);
if(lists == null || lists.size() == 0) {
return null;
}
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(tableName);
//value的格式
StringBuilder pattern = null;
//列
StringBuilder cols = null;
for (Field declaredField : declaredFields) {
String name = declaredField.getName();
if(cols == null) {
cols = new StringBuilder(" ( " + name);
}else {
cols.append(" , ").append(name);
}
if(pattern == null) {
pattern = new StringBuilder("(#'{'lists[{0}]." + name + "} ");
} else {
pattern.append(", #'{'lists[{0}].").append(name).append("} ");
}
}
if(pattern == null) {
return null;
}
pattern.append(")");
cols.append(" ) values ");
sql.append(cols);
MessageFormat mf = new MessageFormat(pattern.toString());
//填充value参数
for (int i = 0; i < lists.size(); i++) {
sql.append(mf.format(new Object[] {i})).append(" ,");
}
sql.deleteCharAt(sql.length() - 1);
return sql.toString();
}
代码解析
我们最后要拼装的sql大概这样
insert into my_table ( col1, col2, col3) values (val1, val2, val3), (val1, val2, val3), (val1, val2, val3)
比较关键的地方在于values后面的n个数据列表。
我的做法是是先构建一个模板:(这里的参数0表示占位符)
(#{lists[0].fieldName}, #{lists[0].fieldName}, #{lists[0].fieldNames})
当然,具体有多少个字段是不知道的,需要用循环构建。
得到pattern后,构建一个MessageFormat对象。
MessageFormat mf = new MessageFormat(pattern.toString());
然后循环的给模板赋值,并将得到的结果拼装到最终的sql中。
for (int i = 0; i < lists.size(); i++) {
sql.append(mf.format(new Object[] {i})).append(" ,");
}