|
|
@@ -16,20 +16,21 @@
|
|
|
|
|
|
package com.jfinal.plugin.activerecord;
|
|
|
|
|
|
+import com.jfinal.kit.StrKit;
|
|
|
+
|
|
|
import java.sql.Connection;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.SQLException;
|
|
|
import java.sql.Statement;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
+import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* DbKit
|
|
|
*/
|
|
|
@SuppressWarnings("rawtypes")
|
|
|
public final class DbKit {
|
|
|
-
|
|
|
+
|
|
|
+ public static final int DB_BATCH_COUNT = 1024;
|
|
|
/**
|
|
|
* The main Config object for system
|
|
|
*/
|
|
|
@@ -134,6 +135,184 @@ public final class DbKit {
|
|
|
String n = modelClass.getName();
|
|
|
return (Class<? extends Model>)(n.indexOf("_$$_") > -1 || n.indexOf("$$Enhancer") > -1 ? modelClass.getSuperclass() : modelClass);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 原有框架方法更新只会取modelList第一个元素的字段状态,批量更新的SQL全部相同,只是参数值不同
|
|
|
+ * 本方法会根据modelList中所有元素,生成不同的SQL和参数,分批分别执行
|
|
|
+ * 自动过滤所有null值属性
|
|
|
+ *
|
|
|
+ * @param modelList
|
|
|
+ * @param batchSize
|
|
|
+ * @param db 使用的数据源,为空时使用默认
|
|
|
+ * @return
|
|
|
+ * @see :https://jfinal.com/share/2629
|
|
|
+ */
|
|
|
+ public static List<Integer> batchListUpdate(List<? extends Model> modelList, int batchSize,String db) {
|
|
|
+ if (modelList == null || modelList.size() == 0)
|
|
|
+ return new ArrayList<>();
|
|
|
+ Map<String, BatchInfo> modelUpdateMap = new HashMap<>();
|
|
|
+
|
|
|
+ for (Model model : modelList) {
|
|
|
+ Set<String> modifyFlag = CPI.getModifyFlag(model);
|
|
|
+ Config config = CPI.getConfig(model);
|
|
|
+ Table table = TableMapping.me().getTable(model.getClass());
|
|
|
+ String[] pKeys = table.getPrimaryKey();
|
|
|
+ Map<String, Object> attrs = CPI.getAttrs(model);
|
|
|
+ List<String> attrNames = new ArrayList<>();
|
|
|
+
|
|
|
+ // the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs
|
|
|
+ for (Map.Entry<String, Object> e : attrs.entrySet()) {
|
|
|
+ String attr = e.getKey();
|
|
|
+ if (modifyFlag.contains(attr) && !config.getDialect().isPrimaryKey(attr, pKeys) && table.hasColumnLabel(attr))
|
|
|
+ attrNames.add(attr);
|
|
|
+ }
|
|
|
+ for (String pKey : pKeys)
|
|
|
+ attrNames.add(pKey);
|
|
|
+ String columns = StrKit.join(attrNames.toArray(new String[attrNames.size()]), ",");
|
|
|
+ BatchInfo updateInfo = modelUpdateMap.get(columns);
|
|
|
+ if (updateInfo == null) {
|
|
|
+ updateInfo = new BatchInfo();
|
|
|
+ updateInfo.list = new ArrayList<>();
|
|
|
+ StringBuilder sql = new StringBuilder();
|
|
|
+ config.getDialect().forModelUpdate(TableMapping.me().getTable(model.getClass()), attrs, modifyFlag, sql, new ArrayList<>());
|
|
|
+ updateInfo.sql = sql.toString();
|
|
|
+ modelUpdateMap.put(columns, updateInfo);
|
|
|
+ }
|
|
|
+ updateInfo.list.add(model);
|
|
|
+ }
|
|
|
+ return batchModelList(modelList, batchSize,db, modelUpdateMap);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListUpdate(List<? extends Model> modelList) {
|
|
|
+ return batchListUpdate(modelList,DB_BATCH_COUNT,null);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListUpdate(List<? extends Model> modelList,String db) {
|
|
|
+ return batchListUpdate(modelList,DB_BATCH_COUNT,db);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static List<Integer> batchModelList(List list, int batchSize, String db, Map<String, BatchInfo> modelUpdateMap) {
|
|
|
+ List<Integer> ret = new ArrayList<>(list.size());
|
|
|
+ DbPro dbPro;
|
|
|
+ if(StrKit.isBlank(db)){
|
|
|
+ dbPro = Db.use();
|
|
|
+ }else{
|
|
|
+ dbPro=Db.use(db);
|
|
|
+ }
|
|
|
+ //批量更新
|
|
|
+ for (Map.Entry<String, BatchInfo> entry : modelUpdateMap.entrySet()) {
|
|
|
+ int[] batch = dbPro.batch(entry.getValue().sql, entry.getKey(), entry.getValue().list, batchSize);
|
|
|
+ for (int i : batch) {
|
|
|
+ ret.add(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 原有框架方法更新只会取modelList第一个元素的字段状态,批量插入的SQL全部相同,只是参数值不同
|
|
|
+ * 本方法会根据modelList中所有元素,生成不同的SQL和参数,分批分别执行
|
|
|
+ * 自动过滤所有null值属性
|
|
|
+ *
|
|
|
+ * @param modelList
|
|
|
+ * @param batchSize
|
|
|
+ * @param db 使用的数据源,为空时使用默认
|
|
|
+ * @return
|
|
|
+ * @see :https://jfinal.com/share/2629
|
|
|
+ */
|
|
|
+ public static List<Integer> batchListSave(List<? extends Model> modelList, int batchSize, String db) {
|
|
|
+ if (modelList == null || modelList.size() == 0)
|
|
|
+ return new ArrayList<>();
|
|
|
+ Map<String, BatchInfo> modelUpdateMap = new HashMap<>();
|
|
|
+
|
|
|
+ for (Model model : modelList) {
|
|
|
+ Config config = CPI.getConfig(model);
|
|
|
+ Map<String, Object> attrs = CPI.getAttrs(model);
|
|
|
+ int index = 0;
|
|
|
+ StringBuilder columns = new StringBuilder();
|
|
|
+ // the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs
|
|
|
+ for (Map.Entry<String, Object> e : attrs.entrySet()) {
|
|
|
+ if (index++ > 0) {
|
|
|
+ columns.append(',');
|
|
|
+ }
|
|
|
+ columns.append(e.getKey());
|
|
|
+ }
|
|
|
+ String cs = columns.toString();
|
|
|
+ BatchInfo batchInfo = modelUpdateMap.get(cs);
|
|
|
+ if (batchInfo == null) {
|
|
|
+ batchInfo = new BatchInfo();
|
|
|
+ batchInfo.list = new ArrayList<>();
|
|
|
+ StringBuilder sql = new StringBuilder();
|
|
|
+ config.getDialect().forModelSave(TableMapping.me().getTable(model.getClass()), attrs, sql, new ArrayList());
|
|
|
+ batchInfo.sql = sql.toString();
|
|
|
+ modelUpdateMap.put(cs, batchInfo);
|
|
|
+ }
|
|
|
+ batchInfo.list.add(model);
|
|
|
+ }
|
|
|
+ return batchModelList(modelList, batchSize, db,modelUpdateMap);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListSave(List<? extends Model> modelList) {
|
|
|
+ return batchListSave(modelList,DB_BATCH_COUNT,null);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListSave(List<? extends Model> modelList,String db) {
|
|
|
+ return batchListSave(modelList,DB_BATCH_COUNT,db);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListSave(String tableName,List<? extends Record> recordList, int batchSize, String db) {
|
|
|
+ if (recordList == null || recordList.size() == 0)
|
|
|
+ return new ArrayList<>();
|
|
|
+ Map<String, BatchInfo> updateMap = new HashMap<>();
|
|
|
+
|
|
|
+ for (Record record : recordList) {
|
|
|
+ Map<String, Object> attrs = record.getColumns();
|
|
|
+ int index = 0;
|
|
|
+ StringBuilder columns = new StringBuilder();
|
|
|
+ // the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs
|
|
|
+ for (Map.Entry<String, Object> e : attrs.entrySet()) {
|
|
|
+ if (index++ > 0) {
|
|
|
+ columns.append(',');
|
|
|
+ }
|
|
|
+ columns.append(e.getKey());
|
|
|
+ }
|
|
|
+ String cs = columns.toString();
|
|
|
+ BatchInfo batchInfo = updateMap.get(cs);
|
|
|
+ if (batchInfo == null) {
|
|
|
+ batchInfo = new BatchInfo();
|
|
|
+ batchInfo.list = new ArrayList<>();
|
|
|
+ StringBuilder sql = new StringBuilder();
|
|
|
+ Db.use().getConfig().getDialect().forDbSave(tableName, new String[0], record, sql, new ArrayList<>());
|
|
|
+ batchInfo.sql = sql.toString();
|
|
|
+ updateMap.put(cs, batchInfo);
|
|
|
+ }
|
|
|
+ batchInfo.list.add(record);
|
|
|
+ }
|
|
|
+ return batchModelList(recordList, batchSize,db, updateMap);
|
|
|
+ }
|
|
|
+ public static List<Integer> batchListSave(String tableName,List<? extends Record> recordList) {
|
|
|
+ return batchListSave(tableName,recordList,DB_BATCH_COUNT,null);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 设置IN查询的sql和参数
|
|
|
+ *
|
|
|
+ * @param paras
|
|
|
+ * @param sb
|
|
|
+ * @param inParas
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static StringBuilder buildInSqlPara(List<Object> paras, StringBuilder sb, Object[] inParas) {
|
|
|
+ sb.append("(");
|
|
|
+ for (int i = 0; i < inParas.length; i++) {
|
|
|
+ paras.add(inParas[i]);
|
|
|
+ if (i < inParas.length - 1) {
|
|
|
+ sb.append("?,");
|
|
|
+ } else {
|
|
|
+ sb.append("?)");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sb;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class BatchInfo {
|
|
|
+ public String sql;
|
|
|
+ public List list;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|