1. 并发处理较大的列表数据的简便写法
CompletableFuture.allOf(MoreStreams.partition(seedList.stream(), PAGE_SIZE).map(seeds ->
CompletableFuture.runAsync(() -> {
// do something
...
}, executorService)
).toArray(CompletableFuture[]::new)).join();
MoreStreams.partition 可以切分多个列表至自己觉得合适的大小(交由线程处理)
CompletableFuture.allOf 将多个 CompletableFuture 聚合起来等待全部处理结束
2. java注解的使用case:简化jdbc样板代码处理
首先建立两个注解类,用于注解pojo类field字段
第一个,DuplicateUpdate类,区分字段是否被覆盖更新
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DuplicateUpdate {
}
第二个,IgnoreSql类 用于区分查询或者更新时候字段是否被处理
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IgnoreSql {
boolean update() default true;
boolean query() default true;
}
第三个,util类 用于拼装sql(查询/更新语句)
public class SqlUtil {
private static final ConcurrentHashMap<Class<?>, List<Field>> CACHED_CLAZZ_FIELD_MAP = new ConcurrentHashMap<>();
public static StringBuilder getInsertSql(Class<?> clazz, String table) {
List<String> fields = getUpdateFields(clazz).stream().map(Field::getName)
.filter(Predicate.isEqual("id").negate()).collect(Collectors.toList());
return new StringBuilder("INSERT INTO ").append("`").append(table).append("`\n")
.append(fields.stream().map(CAMEL_TO_UNDERSCORE)
.map(name -> new StringBuilder("`").append(name).append("`"))
.collect(Collectors.joining(",\n", "(", ")\n")))
.append(fields.stream().map(name -> new StringBuilder(":").append(name))
.collect(Collectors.joining(",\n", "VALUES(", ")")));
}
public static StringBuilder getInsertDuplicateSql(Class<?> clazz, String table) {
List<String> duplicateUpdateFields = getUpdateFields(clazz).stream().filter(DUPLICATE_SQL)
.map(Field::getName).filter(Predicate.isEqual("id").negate())
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(duplicateUpdateFields)) {
return getInsertSql(clazz, table);
}
return getInsertSql(clazz, table).append(duplicateUpdateFields.stream()
.map(name -> new StringBuffer("`").append(CAMEL_TO_UNDERSCORE.apply(name))
.append("` = :").append(name))
.collect(Collectors.joining(",\n", " ON DUPLICATE KEY UPDATE\n", "")));
}
public static StringBuilder getUpdateSql(Class<?> clazz, String table, String primaryProperty) {
List<String> fields = getUpdateFields(clazz).stream().map(Field::getName)
.collect(Collectors.toList());
return new StringBuilder("UPDATE ").append("`").append(table).append("`\n")
.append(fields.stream()
.map(name -> new StringBuffer("`").append(CAMEL_TO_UNDERSCORE.apply(name))
.append("` = :").append(name))
.collect(Collectors.joining(",\n", "SET\n", "\n")))
.append(String.format("WHERE `%s` = :%s",
CAMEL_TO_UNDERSCORE.apply(primaryProperty), primaryProperty));
}
public static StringBuilder getUpdateSqlWithoutPrimaryKey(Class<?> clazz, String table) {
List<String> fields = getUpdateFields(clazz).stream().map(Field::getName)
.collect(Collectors.toList());
return new StringBuilder("UPDATE ").append("`").append(table).append("`\n")
.append(fields.stream()
.map(name -> new StringBuffer("`").append(CAMEL_TO_UNDERSCORE.apply(name))
.append("` = :").append(name))
.collect(Collectors.joining(",\n", "SET\n", "\n")));
}
public static StringBuilder getSelectSql(Class<?> clazz, String table) {
List<String> fields = getSelectFields(clazz).stream().map(Field::getName)
.collect(Collectors.toList());
return new StringBuilder("SELECT ")
.append(fields.stream().map(CAMEL_TO_UNDERSCORE).map(name -> "`" + name + "`")
.collect(Collectors.joining(",")))
.append(" FROM `").append(table).append("`");
}
public static StringBuilder getSelectDistinctSql(Class<?> clazz, String table,
String distinctColumn) {
List<String> fields = getSelectFields(clazz).stream().map(Field::getName)
.collect(Collectors.toList());
return new StringBuilder("SELECT \n").append(String.format("`%s`,\n", distinctColumn))
.append(fields.stream().map(CAMEL_TO_UNDERSCORE)
.filter(columnName -> !distinctColumn.equalsIgnoreCase(columnName))
.map(name -> "MAX(`" + name + "`) AS " + name)
.collect(Collectors.joining(",\n")))
.append("\nFROM `").append(table).append("`");
}
private static List<Field> getFields(Class<?> clazz) {
if (clazz.getSuperclass() == null || clazz.getSuperclass() == Object.class) {
return Arrays.stream(clazz.getDeclaredFields()).filter(Objects::nonNull)
// 过滤掉对象中的静态变量
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.filter(field -> StringUtils.isNotBlank(field.getName()))
.collect(Collectors.toList());
} else {
List<Field> fields = Arrays.stream(clazz.getDeclaredFields()).filter(Objects::nonNull)
// 过滤掉对象中的静态变量
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.filter(field -> StringUtils.isNotBlank(field.getName()))
.collect(Collectors.toList());
fields.addAll(getFields(clazz.getSuperclass()));
return fields;
}
}
private static List<Field> getUpdateFields(Class<?> clazz) {
return getCachedField(clazz).stream().filter(IGNORE_UPDATE_SQL)
.collect(Collectors.toList());
}
private static List<Field> getUpdateByIdFields(Class<?> clazz) {
return getCachedField(clazz).stream().filter(IGNORE_UPDATE_SQL)
.filter(field -> !field.getName().equalsIgnoreCase("id"))
.collect(Collectors.toList());
}
public static StringBuilder getUpdateByIdFields(Class<?> clazz, String table) {
List<String> fields = getUpdateByIdFields(clazz).stream().map(Field::getName)
.collect(Collectors.toList());
return new StringBuilder("UPDATE ").append("`").append(table).append("`\n")
.append(fields.stream()
.map(name -> new StringBuffer("`").append(CAMEL_TO_UNDERSCORE.apply(name))
.append("` = :").append(name))
.collect(Collectors.joining(",\n", "SET\n", "\n")))
.append("WHERE `id` = :id");
}
private static List<Field> getSelectFields(Class<?> clazz) {
return getCachedField(clazz).stream().filter(IGNORE_SELECT_SQL)
.collect(Collectors.toList());
}
private static List<Field> getCachedField(Class<?> clazz) {
List<Field> cachedFieldList = CACHED_CLAZZ_FIELD_MAP.get(clazz);
if (CollectionUtils.isNotEmpty(cachedFieldList)) {
return cachedFieldList;
}
cachedFieldList = getFields(clazz);
CACHED_CLAZZ_FIELD_MAP.putIfAbsent(clazz, cachedFieldList);
return cachedFieldList;
}
private static final Function<String, String> CAMEL_TO_UNDERSCORE = CaseFormat.LOWER_CAMEL
.converterTo(CaseFormat.LOWER_UNDERSCORE)::convert;
private static final Predicate<Field> IGNORE_SELECT_SQL = field -> field
.getAnnotation(IgnoreSql.class) == null
|| (!field.getAnnotation(IgnoreSql.class).query());
private static final Predicate<Field> IGNORE_UPDATE_SQL = field -> field
.getAnnotation(IgnoreSql.class) == null
|| (!field.getAnnotation(IgnoreSql.class).update());
private static final Predicate<Field> DUPLICATE_SQL = field -> Objects
.nonNull(field.getAnnotation(DuplicateUpdate.class));
}