你可以试试这段代码。它将日志存储在 Storage 类中。您可以修改存储以满足您的要求。仅当单个jvm访问 db 时,此代码才有效。这段代码我没有测试过,欢迎指正。
public static void main(String[] args) {
PreparedStatement psmt = new LoggingPreparedStatement(conn.prepareStatement(
" UPDATE tableName SET val1 =?,val2 =?,val3 =?,val4 =? WHERE id = 1 "));
psmt.setString(1, myValue1);
psmt.setString(2, myValue2);
psmt.setString(3, myValue3);
psmt.setString(4, myValue4);
psmt.execute();
for (Trail trail : Storage.INSTANCE.getTrails()) {
System.out.println(trail);
}
}
public static class Trail {
private final int fieldIdx;
private final String prevValue;
private final String currentValue;
private Trail(int fieldIdx, String prevValue, String currentValue) {
this.fieldIdx = fieldIdx;
this.prevValue = prevValue;
this.currentValue = currentValue;
}
public int getFieldIdx() {
return fieldIdx;
}
public String getPrevValue() {
return prevValue;
}
public String getCurrentValue() {
return currentValue;
}
@Override
public String toString() {
return "Trail{" +
"fieldIdx=" + fieldIdx +
", prevValue='" + prevValue + '\'' +
", currentValue='" + currentValue + '\'' +
'}';
}
}
public enum Storage {
INSTANCE;
private final ConcurrentMap<Integer, String> lastValues = new ConcurrentHashMap<Integer, String>();
private final Queue<Trail> trails = new ConcurrentLinkedQueue<Trail>();
private final Object lock = new Object();
public void putTrailIfNecessary(int idx, String newValue) {
String lastValue = lastValues.get(idx);
if (lastValue == null ? newValue != null : !lastValue.equals(newValue)) {
synchronized (lock) {
String lastValue1 = lastValues.get(idx);
if (lastValue1 == null ? newValue != null : !lastValue1.equals(newValue)) {
lastValues.put(idx, newValue);
trails.add(new Trail(idx, lastValue1, newValue));
}
}
}
}
public List<Trail> getTrails() {
return new ArrayList<Trail>(trails);
}
}
public static class LoggingPreparedStatement
implements PreparedStatement {
private final PreparedStatement delegate;
public LoggingPreparedStatement(PreparedStatement delegate) {
this.delegate = delegate;
}
// this we put audit trail
@Override
public void setString(int parameterIndex, String x)
throws SQLException {
Storage.INSTANCE.putTrailIfNecessary(parameterIndex, x);
delegate.setString(parameterIndex, x);
}
@Override
public ResultSet executeQuery()
throws SQLException {return delegate.executeQuery();}
@Override
public int executeUpdate()
throws SQLException {return delegate.executeUpdate();}
@Override
public void setNull(int parameterIndex, int sqlType)
throws SQLException {delegate.setNull(parameterIndex, sqlType);}
@Override
public void setBoolean(int parameterIndex, boolean x)
throws SQLException {delegate.setBoolean(parameterIndex, x);}
@Override
public void setByte(int parameterIndex, byte x)
throws SQLException {delegate.setByte(parameterIndex, x);}
@Override
public void setShort(int parameterIndex, short x)
throws SQLException {delegate.setShort(parameterIndex, x);}
@Override
public void setInt(int parameterIndex, int x)
throws SQLException {delegate.setInt(parameterIndex, x);}
@Override
public void setLong(int parameterIndex, long x)
throws SQLException {delegate.setLong(parameterIndex, x);}
@Override
public void setFloat(int parameterIndex, float x)
throws SQLException {delegate.setFloat(parameterIndex, x);}
@Override
public void setDouble(int parameterIndex, double x)
throws SQLException {delegate.setDouble(parameterIndex, x);}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x)
throws SQLException {delegate.setBigDecimal(parameterIndex, x);}
@Override
public void setBytes(int parameterIndex, byte[] x)
throws SQLException {delegate.setBytes(parameterIndex, x);}
@Override
public void setDate(int parameterIndex, Date x)
throws SQLException {delegate.setDate(parameterIndex, x);}
@Override
public void setTime(int parameterIndex, Time x)
throws SQLException {delegate.setTime(parameterIndex, x);}
@Override
public void setTimestamp(int parameterIndex,
Timestamp x)
throws SQLException {delegate.setTimestamp(parameterIndex, x);}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length)
throws SQLException {delegate.setAsciiStream(parameterIndex, x, length);}
@Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length)
throws SQLException {delegate.setUnicodeStream(parameterIndex, x, length);}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length)
throws SQLException {delegate.setBinaryStream(parameterIndex, x, length);}
@Override
public void clearParameters()
throws SQLException {delegate.clearParameters();}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType)
throws SQLException {delegate.setObject(parameterIndex, x, targetSqlType);}
@Override
public void setObject(int parameterIndex, Object x)
throws SQLException {delegate.setObject(parameterIndex, x);}
@Override
public boolean execute()
throws SQLException {return delegate.execute();}
@Override
public void addBatch()
throws SQLException {delegate.addBatch();}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length)
throws SQLException {delegate.setCharacterStream(parameterIndex, reader, length);}
@Override
public void setRef(int parameterIndex, Ref x)
throws SQLException {delegate.setRef(parameterIndex, x);}
@Override
public void setBlob(int parameterIndex, Blob x)
throws SQLException {delegate.setBlob(parameterIndex, x);}
@Override
public void setClob(int parameterIndex, Clob x)
throws SQLException {delegate.setClob(parameterIndex, x);}
@Override
public void setArray(int parameterIndex, Array x)
throws SQLException {delegate.setArray(parameterIndex, x);}
@Override
public ResultSetMetaData getMetaData()
throws SQLException {return delegate.getMetaData();}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal)
throws SQLException {delegate.setDate(parameterIndex, x, cal);}
@Override
public void setTime(int parameterIndex, Time x, Calendar cal)
throws SQLException {delegate.setTime(parameterIndex, x, cal);}
@Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
throws SQLException {delegate.setTimestamp(parameterIndex, x, cal);}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName)
throws SQLException {delegate.setNull(parameterIndex, sqlType, typeName);}
@Override
public void setURL(int parameterIndex, URL x)
throws SQLException {delegate.setURL(parameterIndex, x);}
@Override
public ParameterMetaData getParameterMetaData()
throws SQLException {return delegate.getParameterMetaData();}
@Override
public void setRowId(int parameterIndex, RowId x)
throws SQLException {delegate.setRowId(parameterIndex, x);}
@Override
public void setNString(int parameterIndex, String value)
throws SQLException {delegate.setNString(parameterIndex, value);}
@Override
public void setNCharacterStream(int parameterIndex, Reader value, long length)
throws SQLException {delegate.setNCharacterStream(parameterIndex, value, length);}
@Override
public void setNClob(int parameterIndex, NClob value)
throws SQLException {delegate.setNClob(parameterIndex, value);}
@Override
public void setClob(int parameterIndex, Reader reader, long length)
throws SQLException {delegate.setClob(parameterIndex, reader, length);}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length)
throws SQLException {delegate.setBlob(parameterIndex, inputStream, length);}
@Override
public void setNClob(int parameterIndex, Reader reader, long length)
throws SQLException {delegate.setNClob(parameterIndex, reader, length);}
@Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject)
throws SQLException {delegate.setSQLXML(parameterIndex, xmlObject);}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
throws SQLException {delegate.setObject(parameterIndex, x, targetSqlType, scaleOrLength);}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length)
throws SQLException {delegate.setAsciiStream(parameterIndex, x, length);}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length)
throws SQLException {delegate.setBinaryStream(parameterIndex, x, length);}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length)
throws SQLException {delegate.setCharacterStream(parameterIndex, reader, length);}
@Override
public void setAsciiStream(int parameterIndex, InputStream x)
throws SQLException {delegate.setAsciiStream(parameterIndex, x);}
@Override
public void setBinaryStream(int parameterIndex, InputStream x)
throws SQLException {delegate.setBinaryStream(parameterIndex, x);}
@Override
public void setCharacterStream(int parameterIndex, Reader reader)
throws SQLException {delegate.setCharacterStream(parameterIndex, reader);}
@Override
public void setNCharacterStream(int parameterIndex, Reader value)
throws SQLException {delegate.setNCharacterStream(parameterIndex, value);}
@Override
public void setClob(int parameterIndex, Reader reader)
throws SQLException {delegate.setClob(parameterIndex, reader);}
@Override
public void setBlob(int parameterIndex, InputStream inputStream)
throws SQLException {delegate.setBlob(parameterIndex, inputStream);}
@Override
public void setNClob(int parameterIndex, Reader reader)
throws SQLException {delegate.setNClob(parameterIndex, reader);}
@Override
public ResultSet executeQuery(String sql)
throws SQLException {return delegate.executeQuery(sql);}
@Override
public int executeUpdate(String sql)
throws SQLException {return delegate.executeUpdate(sql);}
@Override
public void close()
throws SQLException {delegate.close();}
@Override
public int getMaxFieldSize()
throws SQLException {return delegate.getMaxFieldSize();}
@Override
public void setMaxFieldSize(int max)
throws SQLException {delegate.setMaxFieldSize(max);}
@Override
public int getMaxRows()
throws SQLException {return delegate.getMaxRows();}
@Override
public void setMaxRows(int max)
throws SQLException {delegate.setMaxRows(max);}
@Override
public void setEscapeProcessing(boolean enable)
throws SQLException {delegate.setEscapeProcessing(enable);}
@Override
public int getQueryTimeout()
throws SQLException {return delegate.getQueryTimeout();}
@Override
public void setQueryTimeout(int seconds)
throws SQLException {delegate.setQueryTimeout(seconds);}
@Override
public void cancel()
throws SQLException {delegate.cancel();}
@Override
public SQLWarning getWarnings()
throws SQLException {return delegate.getWarnings();}
@Override
public void clearWarnings()
throws SQLException {delegate.clearWarnings();}
@Override
public void setCursorName(String name)
throws SQLException {delegate.setCursorName(name);}
@Override
public boolean execute(String sql)
throws SQLException {return delegate.execute(sql);}
@Override
public ResultSet getResultSet()
throws SQLException {return delegate.getResultSet();}
@Override
public int getUpdateCount()
throws SQLException {return delegate.getUpdateCount();}
@Override
public boolean getMoreResults()
throws SQLException {return delegate.getMoreResults();}
@Override
public void setFetchDirection(int direction)
throws SQLException {delegate.setFetchDirection(direction);}
@Override
public int getFetchDirection()
throws SQLException {return delegate.getFetchDirection();}
@Override
public void setFetchSize(int rows)
throws SQLException {delegate.setFetchSize(rows);}
@Override
public int getFetchSize()
throws SQLException {return delegate.getFetchSize();}
@Override
public int getResultSetConcurrency()
throws SQLException {return delegate.getResultSetConcurrency();}
@Override
public int getResultSetType()
throws SQLException {return delegate.getResultSetType();}
@Override
public void addBatch(String sql)
throws SQLException {delegate.addBatch(sql);}
@Override
public void clearBatch()
throws SQLException {delegate.clearBatch();}
@Override
public int[] executeBatch()
throws SQLException {return delegate.executeBatch();}
@Override
public Connection getConnection()
throws SQLException {return delegate.getConnection();}
@Override
public boolean getMoreResults(int current)
throws SQLException {return delegate.getMoreResults(current);}
@Override
public ResultSet getGeneratedKeys()
throws SQLException {return delegate.getGeneratedKeys();}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys)
throws SQLException {return delegate.executeUpdate(sql, autoGeneratedKeys);}
@Override
public int executeUpdate(String sql, int[] columnIndexes)
throws SQLException {return delegate.executeUpdate(sql, columnIndexes);}
@Override
public int executeUpdate(String sql, String[] columnNames)
throws SQLException {return delegate.executeUpdate(sql, columnNames);}
@Override
public boolean execute(String sql, int autoGeneratedKeys)
throws SQLException {return delegate.execute(sql, autoGeneratedKeys);}
@Override
public boolean execute(String sql, int[] columnIndexes)
throws SQLException {return delegate.execute(sql, columnIndexes);}
@Override
public boolean execute(String sql, String[] columnNames)
throws SQLException {return delegate.execute(sql, columnNames);}
@Override
public int getResultSetHoldability()
throws SQLException {return delegate.getResultSetHoldability();}
@Override
public boolean isClosed()
throws SQLException {return delegate.isClosed();}
@Override
public void setPoolable(boolean poolable)
throws SQLException {delegate.setPoolable(poolable);}
@Override
public boolean isPoolable()
throws SQLException {return delegate.isPoolable();}
@Override
public <T> T unwrap(Class<T> iface)
throws SQLException {return delegate.unwrap(iface);}
@Override
public boolean isWrapperFor(Class<?> iface)
throws SQLException {return delegate.isWrapperFor(iface);}
}