/** 判断两条记录是否可以作为一个batch提交,主要判断sql是否相等. 可优先通过schemaName进行判断 */ private boolean canBatch(EventData source, EventData target) { // return StringUtils.equals(source.getSchemaName(), target.getSchemaName()) // && StringUtils.equals(source.getTableName(), target.getTableName()) // && StringUtils.equals(source.getSql(), target.getSql()); // return StringUtils.equals(source.getSql(), target.getSql()); // 因为sqlTemplate构造sql时用了String.intern()的操作,保证相同字符串的引用是同一个,所以可以直接使用==进行判断,提升效率 return source.getSql() == target.getSql(); }
// 大致估算一下row记录的大小 private long calculateSize(EventData data) { // long size = 0L; // size += data.getKeys().toString().getBytes().length - 12 - data.getKeys().size() + 1L; // size += data.getColumns().toString().getBytes().length - 12 - data.getKeys().size() + 1L; // return size; // byte[] bytes = JsonUtils.marshalToByte(data);// 走序列化的方式快速计算一下大小 // return bytes.length; return data.getSize(); // 数据不做计算,避免影响性能 }
private void processStat(EventData data, int affect, boolean batch) { if (batch && (affect < 1 && affect != Statement.SUCCESS_NO_INFO)) { failedDatas.add(data); // 记录到错误的临时队列,进行重试处理 } else if (!batch && affect < 1) { failedDatas.add(data); // 记录到错误的临时队列,进行重试处理 } else { processedDatas.add(data); // 记录到成功的临时队列,commit也可能会失败。所以这记录也可能需要进行重试 DbLoadCounter counter = context.getCounters().get(Arrays.asList(data.getSchemaName(), data.getTableName())); EventType type = data.getEventType(); if (type.isInsert()) { counter.getInsertCount().incrementAndGet(); } else if (type.isUpdate()) { counter.getUpdateCount().incrementAndGet(); } else if (type.isDelete()) { counter.getDeleteCount().incrementAndGet(); } counter.getRowSize().addAndGet(calculateSize(data)); } }
private void doPreparedStatement( PreparedStatement ps, DbDialect dbDialect, LobCreator lobCreator, EventData data) throws SQLException { EventType type = data.getEventType(); // 注意insert/update语句对应的字段数序都是将主键排在后面 List<EventColumn> columns = new ArrayList<EventColumn>(); if (type.isInsert()) { columns.addAll(data.getColumns()); // insert为所有字段 columns.addAll(data.getKeys()); } else if (type.isDelete()) { columns.addAll(data.getKeys()); } else if (type.isUpdate()) { boolean existOldKeys = !CollectionUtils.isEmpty(data.getOldKeys()); columns.addAll(data.getUpdatedColumns()); // 只更新带有isUpdate=true的字段 columns.addAll(data.getKeys()); if (existOldKeys) { columns.addAll(data.getOldKeys()); } } for (int i = 0; i < columns.size(); i++) { int paramIndex = i + 1; EventColumn column = columns.get(i); int sqlType = column.getColumnType(); // 获取一下当前字段名的数据是否必填 Table table = dbDialect.findTable(data.getSchemaName(), data.getTableName()); Map<String, Boolean> isRequiredMap = new HashMap<String, Boolean>(); for (Column tableColumn : table.getColumns()) { isRequiredMap.put(StringUtils.lowerCase(tableColumn.getName()), tableColumn.isRequired()); } Boolean isRequired = isRequiredMap.get(StringUtils.lowerCase(column.getColumnName())); if (isRequired == null) { throw new ClaveException( String.format( "column name %s is not found in Table[%s]", column.getColumnName(), table.toString())); } Object param = SqlUtils.stringToSqlValue( column.getColumnValue(), sqlType, isRequired, dbDialect.isEmptyStringNulled()); try { switch (sqlType) { case Types.CLOB: lobCreator.setClobAsString(ps, paramIndex, (String) param); break; case Types.BLOB: lobCreator.setBlobAsBytes(ps, paramIndex, (byte[]) param); break; default: StatementCreatorUtils.setParameterValue(ps, paramIndex, sqlType, null, param); break; } } catch (SQLException ex) { logger.error( "## SetParam error , [table={}, sqltype={}, value={}]", new Object[] {data.getSchemaName() + "." + data.getTableName(), sqlType, param}); throw ex; } } }