关于批量更新的另类办法

        /**
	 * 为model的每个属性生成一个index
	 * @param model
	 * @return
	 */
	public static Map<String, Integer> orderKey(Model<?> model) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		Set<String> set = CPI.getTable(model).getColumnNameSet();
		int index = 0;
		for(String key : set) {
			map.put(key, index++);
		}
		return map;
	}
	
	/**
	 * 给每个model生成一个key用于分类
	 * 根据model内值不为空的属性对应index进行组合
	 * @param model
	 * @param orderKey
	 * @return
	 */
	public static int batchKey(Model<?> model, Map<String, Integer> orderKey) {
		Set<Entry<String, Object>> entrySet = model._getAttrsEntrySet();
		int[] array = new int[entrySet.size()];
		for(Entry<String, Object> entry : entrySet) {
			if(entry.getValue() != null) {
				array[orderKey.get(entry.getKey())] = 1;
			}
		}
		return binary(array);
	}
	
	public static int binary(int[] array) {
		StringBuilder sb = new StringBuilder();
		for (int s : array) {
			sb.append(s);
		}
		return Integer.parseInt(sb.toString(), 2);
	}
	
	/**
	 * 分类执行批量处理
	 * @param list
	 * @return
	 */
	public static List<int[]> batch(List<Model<?>> list) {
		Map<String, Integer> orderKey = orderKey(list.get(0));
		Map<Integer, List<Model<?>>> batchMap = new HashMap<Integer, List<Model<?>>>();
		for(Model<?> model : list) {
			int mapKey = batchKey(model, orderKey);
			List<Model<?>> batchList = batchMap.get(mapKey);
			if(batchList == null) {
				batchList = batchMap.put(mapKey, new ArrayList<Model<?>>());
			}
			batchList.add(model);
		}
		List<int[]> returns = new ArrayList<int[]>();
		batchMap.forEach((key, value) -> returns.add(Db.batchUpdate(value, 100)));
		return returns;
	}

代码没测试过,只提供思路。

主要就是解决Db批量更新时,集合内每个model的属性值不一致导致有些model的属性更新时漏掉。

那么,把集合内每个model根据每个属性是否有值进行分类,处理成多个集合,再循环进行批处理。

评论区

JFinal

2021-01-28 17:07

是个办法,但比较麻烦,还不如 batch 操作前先对所有 model 迭代扫描,找出拥有最多字段个数的 model,以它为蓝本生成 sql

但上面方法也有缺陷,因为最多字段个数的 model 在如下情况下也不能作为生成 sql 的蓝本,例如:
1:假定 model a 拥有 a,b,c 三个字段值
2:假定 model b 拥有 b,c,d 三个字段值
3:以上情况,字段值数量是一致的,但字段名本身不一致
4:当然,可以更进一步,在迭代的时候获取所有字段名来生成 sql,得到 a,b,c,d 四个字段

JFinal

2021-01-28 17:11

目前感觉比较好的办法是:
1:迭代所有 model,获取这些 model 中所涉及的所有字段名
2:以所有字段名为蓝本生成 sql,这样就不会漏掉字段名了
3:但还是解决不了那些 model 中没有指定字段值要给定什么值的问题,给定 null 值可能是不适合的,因为这个字段在数据库中可能已经有值了,给定 null 值相当于是将其删掉

有时候吧,我们做越多,涌现出的问题也就越多,当解决一个问题的时候如果冒出来的问题个数相等或者更多,或者更麻烦,那还不如不解决, 而是约定、限制我们自己的行为

doubuxingle

2021-01-29 11:16

我这个是在批量更新表格数据的时候用上的,每天有个几百万的数据,因此只能使用批量更新,不然一个一个更新人都要等崩溃。
少量数据直接Db.batch(sqlList, batchSize) 可能还方便点。