6

我所拥有的是下表。

+----+--------+--------+--------+--------+
| id |  val1  |  val2  |  val3  |  val4  |
+====+========+========+========+========+
| 1  |  data1 |  data2 |  data3 |  data4 |
+----+--------+--------+--------+--------+

现在我发出一个带有以下详细信息的查询,比如说

UPDATE tableName 
SET val1='newVal1', val2='data2', val3='data3', val4='data4' 
WHERE id=1

注意:这只是相同的查询。实际上我正在从四个文本字段实现编辑。所以我将使用 JSF 和 Java bean 将如下所示。

PreparedStatement psmt = 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();

我想要的是使用上面的查询,更新哪些列。在上述情况下,val1列已更新。

基本上我想要这个用于日志目的,在那里我会知道谁做了编辑以及做了什么编辑。任何想法/建议如何完成这项工作?

注意: 我不想创建任何其他表,如 meewoK 的回答中所述。只是使用查询,我想知道更新的列名。


我会用例子解释我想要什么。

假设userA登录到系统。现在他可以访问用户列表。现在假设他为User B进行了编辑。他更改的是用户 B、电子邮件 ID 和全名。现在在日志中我想要的是两个条目。

=================================================================
whoDid  whatDid forWhom   whichField   whichSection whatTime
=================================================================
userA   edit    userB     emailId      User         time_whenDid
userA   edit    userB     fullName     User         time_whenDid
=================================================================
4

4 回答 4

6

如何在更新之前运行类似以下查询来创建日志条目:

PreparedStatement psmt = conn.prepareStatement("
    SELECT CASE WHEN val1 = ?
                THEN ''
                ELSE 'val1 changed from ' + val1 + ' to ' + ? + '\n'
           END CASE +
           CASE WHEN val2 = ?
                THEN ''
                ELSE 'val2 changed from ' + val2 + ' to ' + ? + '\n'
           END CASE +
           CASE WHEN val3 = ?
                THEN ''
                ELSE 'val3 changed from ' + val3 + ' to ' + ? + '\n'
           END CASE +
           CASE WHEN val4 = ?
                THEN ''
                ELSE 'val4 changed from ' + val4 + ' to ' + ? + '\n'
           END CASE AS logentry
    FROM tableName
    WHERE id=1
");
psmt.setString(1, myValue1);
psmt.setString(2, myValue1);
psmt.setString(3, myValue2);
psmt.setString(4, myValue2);
psmt.setString(5, myValue3);
psmt.setString(6, myValue3);
psmt.setString(7, myValue4);
psmt.setString(8, myValue4);
ResultSet rs = psmt.executeQuery();
String logentry = rs.getString("logentry");

免责声明:这超出了我的想法,并且完全未经测试,因此可能需要进行一些调整-应该足以让您继续前进。

可能的问题:即使您在更新之前执行查询,也有可能两者之间的数据发生了变化。根据各种因素,这在实践中可能是也可能不是问题,但值得一提。

于 2013-08-13T20:55:34.293 回答
2

你可以试试这段代码。它将日志存储在 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);}
}
于 2013-08-15T16:21:40.417 回答
1

您可以执行以下操作之一:

  1. 在 mysql 中创建一个存储过程,它会检查并更新第二个表。
  2. 创建一个可更新视图并在一个查询(UPDATE、SET 和 CASE)中使用 MySQL 更新条件,这将检查更新值是否与当前值不同并更新一个标志。
  3. 根据原始值是什么以及客户端中的哪些字段已更改,请检查客户端。

如果您真的想在一次查询中执行此操作,一种有趣的方法是选项 2...

选项 2

1) 创建第二个名为 tableNamePrevious 的表,其中包含以下字段:

+ id_prev +  val1_prev  +  val2_prev  +  val3_prev  +  val4_prev  ...

进行更改时,此表将存储以前的值。如果未进行任何更改 (NULL) 将被输入。

2)使用以下查询创建一个 UPDATABLE 视图(此处遵循规则:http: //dev.mysql.com/doc/refman//5.5/en/view-updatability.html

create view tableNameView as select * from tableName, tableNamePrevious where tableName.id = tableNamePrevious.id_prev;

3) 在视图上运行更新,使用更新中的条件:

update tableNameView 
    SET val1_prev = CASE
        WHEN val1 = INPUT_VAL1 THEN NULL
        WHEN NOT val1 = INPUT_VAL1 THEN val1
    END,
    val2_prev = CASE
        WHEN val2 = INPUT_VAL2 THEN NULL
        WHEN NOT val2 = INPUT_VAL2 THEN val2
    END,
    ... ,
    val1='newVal1', val2='data2', ... ,
    where id = INPUT_ID;

因此,当新的 INPUT_VALUE 与现有的不同时,第二个表中的字段将是旧值。否则它将为空。

使用向上数据表视图意味着您更新表和包含更改的日志表。

case 语句意味着您可以检查新的输入值是否与以前的不同。

于 2013-04-28T11:39:44.967 回答
0

您是否考虑过使用触发器?这是基于Wikipedia中的示例:

CREATE TRIGGER user_trigger
    BEFORE UPDATE ON user_table
    REFERENCING NEW ROW AS n, OLD ROW AS o
    FOR EACH ROW
    IF n.val1 <> o.val1 THEN
        INSERT INTO Log (whoDid, whatDid, ...) VALUES (..., 'edit', ...)
    END IF;
;
于 2013-08-20T19:43:58.047 回答