用过mybatis都清楚tk-mapper
tk-mapper 批量保存操作不知道用过没有 感觉很鸡肋就是动态拼接批量插入语句
效率低就算了 可是还硬性规定 接口限制实体包含id
属性并且必须为自增列
并且字段为null也会插入 想想心都累了 有的字段有默认值 你插入null 数据库统统报错
搞了很久终于把字段为null这一诟病给治好了
利用注解和反射给字段标注默认值
1. 定义默认值注解
package ;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public interface TableField {
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultStringValue {
String value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultIntValue {
int value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultDoubleValue {
double value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultBooleanValue {
boolean value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultCharValue {
char value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnDefaultDateValue {
String value() default "";
}
}
2. 重写框架自带的批量插入方法
package ;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.collect.Lists;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.experimental.Accessors;
import tk.mybatis.mapper.common.MySqlMapper;
@SuppressWarnings("unchecked")
public interface BatchInsertListMapper<T> extends MySqlMapper<T> {
default int batchInsertList(List<? extends T> recordList) {
new BatchInsertListMapper.Inner<T>().fillFieldDefaultValue(recordList);
List<?> partition = Lists.partition(recordList, Inner.BATCH_SIZE);
int effectRow = 0;
for (Object item : partition) {
effectRow += insertList((List<? extends T>) item);
}
return effectRow;
};
@Accessors(chain = true)
class Inner<T> {
private static final String PRIMARY_ID = "id";
private static final int BATCH_SIZE = 1000;
private static final String ANNOTATION_DEFAULT_ATTRIBUTE = "value";
private static final Map<String, Object> FIELD_DEFAULT_VALUE_MAP = new ConcurrentHashMap<>();
private static final String TABLE_FIELD_ANNOTATION_BASE_PACKAGE = TableField.class.getPackage().getName();
private static final Set<Class<?>> ANNOTATION_CLASSES = ClassUtil.scanPackage(
TABLE_FIELD_ANNOTATION_BASE_PACKAGE,
clazz -> clazz != null && clazz.isAnnotation() && clazz.getName().contains(TableField.class.getName()));
private void fillFieldDefaultValue(List<? extends T> recordList) {
try {
for (T item : recordList) {
Field[] fields = ReflectUtil.getFields(item.getClass());
for (Field field : fields) {
if (ReflectUtil.getFieldValue(item, field) == null
|| !Objects.equals(field.getName(), PRIMARY_ID)) {
Object object = FIELD_DEFAULT_VALUE_MAP.get(field.toGenericString());
if (object != null) {
ReflectUtil.setFieldValue(item, field, object);
} else {
searchFieldDefaultValue(item, field);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void searchFieldDefaultValue(T item, Field field) {
for (Class<?> clazz : ANNOTATION_CLASSES) {
Map<String, Object> annotationValueMap = AnnotationUtil.getAnnotationValueMap(field,
(Class<? extends Annotation>) clazz);
if (MapUtil.isNotEmpty(annotationValueMap)) {
Object fillValue = annotationValueMap.get(ANNOTATION_DEFAULT_ATTRIBUTE);
if ((fillValue.getClass() == Double.class
&& field.getType() == BigDecimal.class) ? true : field.getType() == fillValue.getClass()) {
ReflectUtil.setFieldValue(item, field, fillValue);
FIELD_DEFAULT_VALUE_MAP.put(field.toGenericString(), fillValue);
}
if (field.isAnnotationPresent(ColumnDefaultDateValue.class)) {
ReflectUtil.setFieldValue(item, field, new Date());
}
}
}
}
}
}
3. 声明定义的批量插入接口
package ;
import tk.mybatis.mapper.annotation.RegisterMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.Marker;
@RegisterMapper
public interface CoreMapper<T> extends Mapper<T>, BatchInsertListMapper<T>, Marker {
}
至此项目中只要 dao 层继承 CoreMapper 接口即可获取批量插入功能并且会插入字段默认值(字段本身有值不会覆盖)