package com.taobao.yugong.common.db; import java.lang.reflect.Array; import java.math.BigDecimal; import java.text.MessageFormat; import java.util.Date; import java.util.List; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.taobao.yugong.common.audit.RecordDumper; import com.taobao.yugong.common.db.meta.ColumnValue; import com.taobao.yugong.common.model.record.Record; import com.taobao.yugong.exception.YuGongException; /** * 记录对比 * * @author agapple 2013-9-29 下午2:56:39 */ public class RecordDiffer { private static final String SEP = SystemUtils.LINE_SEPARATOR; private static String record_format = null; private static final Logger diffLogger = LoggerFactory.getLogger("check"); static { record_format = SEP + "-----------------" + SEP; record_format += "- Schema: {0} , Table: {1}" + SEP; record_format += "-----------------" + SEP; record_format += "---Pks" + SEP; record_format += "{2}" + SEP; record_format += "---diff" + SEP; record_format += "\t{3}" + SEP; } public static void diff(Record record1, Record record2) { if (record2 == null) { diffLogger.info(diffMessage(record1.getSchemaName(), record1.getTableName(), record1.getPrimaryKeys(), "record not found")); return; } if (record1.getColumns().size() > record2.getColumns().size()) { diffLogger.info(diffMessage(record1.getSchemaName(), record1.getTableName(), record1.getPrimaryKeys(), "column size is great than target column size")); return; } StringBuilder diff = new StringBuilder(); boolean same = true; int size = record1.getColumns().size(); for (int i = 0; i < size; i++) { ColumnValue column = record1.getColumns().get(i); same &= campareOneColumn(column, getColumn(record2, column.getColumn().getName()), diff); } if (!same) { diffLogger.info(diffMessage(record1.getSchemaName(), record2.getTableName(), record1.getPrimaryKeys(), diff.toString())); } } private static boolean campareOneColumn(ColumnValue column1, ColumnValue column2, StringBuilder diff) { if (!column1.isCheck() || !column2.isCheck()) { return true;// 可能不需要做对比,忽略 } Object value1 = column1.getValue(); Object value2 = column2.getValue(); if (value1 == null && value2 == null) { return true; } StringBuilder message = new StringBuilder(); message.append(column1.getColumn()) .append(" , values : [") .append(ObjectUtils.toString(value1)) .append("] vs [") .append(ObjectUtils.toString(value2)) .append("]\n\t"); if ((value1 == null && value2 != null) || (value1 != null && value2 == null)) { diff.append(message); return false; } if (!value1.equals(value2)) { // custom define if (value1 instanceof java.util.Date && value2 instanceof java.util.Date) { boolean result = dateValueEquals((java.util.Date) value1, (java.util.Date) value2); if (!result) { String v1 = value1.toString(); String v2 = value2.toString(); // 2012-02-02 02:02:02 与 2012-02-02 肯定是一种包含关系 if (v1.contains(v2) || v2.contains(v1)) { return true; } } else { return true; } } else if (Number.class.isAssignableFrom(value1.getClass()) && Number.class.isAssignableFrom(value2.getClass())) { String v1 = null; String v2 = null; v1 = getNumberString(value1); v2 = getNumberString(value2); boolean result = v1.equals(v2); if (result) { return true; } } else if (value1.getClass().isArray() && value2.getClass().isArray()) { boolean result = true; if (Array.getLength(value1) == Array.getLength(value2)) { int length = Array.getLength(value1); for (int i = 0; i < length; i++) { result &= ObjectUtils.equals(Array.get(value1, i), Array.get(value2, i)); } if (result) { return true; } } } // 其他情况为false diff.append(message); return false; } else { return true; } } private static String getNumberString(Object value1) { String v1; if (value1 instanceof BigDecimal) { v1 = ((BigDecimal) value1).toPlainString(); if (StringUtils.indexOf(v1, ".") != -1) { v1 = StringUtils.stripEnd(v1, "0");// 如果0是末尾,则删除之 v1 = StringUtils.stripEnd(v1, ".");// 如果.是末尾,则删除之 } } else { v1 = value1.toString(); } return v1; } private static boolean dateValueEquals(Date source, Date target) { return source.getTime() == target.getTime(); } private static ColumnValue getColumn(Record record, String columnName) { for (ColumnValue column : record.getColumns()) { if (StringUtils.equalsIgnoreCase(columnName, column.getColumn().getName())) { return column; } } throw new YuGongException("column[" + columnName + "] is not found."); } private static String diffMessage(String schemaName, String tableName, List<ColumnValue> primaryKeys, String message) { return MessageFormat.format(record_format, schemaName, tableName, RecordDumper.dumpRecordColumns(primaryKeys), message); } }