列出所有已更新的列名

时间:2013-04-28 11:01:04

标签: java mysql jdbc sql-update prepared-statement

我的内容如下表所示。

+----+--------+--------+--------+--------+
| 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 已登录系统。现在他可以访问用户列表了。现在让我们说他确实编辑了用户B 。他改变的是用户B,电子邮件ID和全名。 现在在日志中我想要的是两个条目。

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

4 个答案:

答案 0 :(得分: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");

免责声明:这是我的头脑,并且完全没有经过测试,所以可能需要进行一些调整 - 应该足以让你顺利。

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

答案 1 :(得分:2)

您可以尝试使用此代码。它将日志记录存储在Storage类中。您可以修改存储以满足您的要求。此代码仅在 jvm访问数据库时有效。我没有测试过这段代码,所以我欢迎更正。

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);}
}

答案 2 :(得分:1)

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

  1. 在mysql中创建一个存储过程,用于检查和更新第二个表。
  2. 创建一个可更新的视图并使用MySQL update conditions in one query (UPDATE, SET & CASE),它将检查更新值是否与当前值不同并更新标志。
  3. 根据原始值和客户端中的哪些字段进行更改,检查客户端。
  4. 如果你真的想在一次查询中做到这一点,一个有趣的方法是选项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与现有的不同时,第二个表中的字段将是旧值。 否则它将为null。

    使用up datable视图意味着您同时更新表和包含更改的日志表。

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

答案 3 :(得分: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;
;