Browse Source

!111 Dbkit分组批量更新、插入
Merge pull request !111 from 大个/master

JFinal 2 years ago
parent
commit
b8b43e4292
1 changed files with 183 additions and 4 deletions
  1. 183 4
      src/main/java/com/jfinal/plugin/activerecord/DbKit.java

+ 183 - 4
src/main/java/com/jfinal/plugin/activerecord/DbKit.java

@@ -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;
+	}
 }