Оба требуют, чтобы вызывающему было предоставлено SeSystemTimePrivilege и эта привилегия включена.
Вы очень смущены, но, по крайней мере, все выглядит лучше после ваших изменений. Существует несколько способов сделать это, но лучший способ, который я нашел, - фактически использовать методы JDBC ResultSet.update*
:
. Сначала вам нужно подготовить инструкцию SELECT ... FOR UPDATE
к аргументу ResultSet.CONCUR_UPDATABLE
, например:
ps = conn.prepareStatement(query,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
Затем вы должны фактически обновить таблицу, используя ResultSet:
if(rs.next())
{
rs.updateString(columnIndex, "new_hostname");
rs.updateRow();
}
В-третьих, вам, вероятно, придется использовать транзакцию, см. в своем обновлении. Надеемся, что ваши методы DbUtil.close
не будут исключать какие-либо исключения, проверять значение null и т. Д. Кроме того, если ваш метод становится более сложным, у вас также должна быть логика отката.
Вы не должны по какой-либо причине необходимо изменить my.ini
.
Соединение, которое вы создаете, выбирающее для обновления, должно быть таким же, как и для обновления. В противном случае он не является частью одной и той же транзакции и освобождает блокировку, поэтому ваши другие потоки начинают ее выполнять. Поэтому в вашем коде вам нужно сделать это:
if (rs.first())
{
String s = rs.getString("HostName");
oid = rs.getLong("OID");
System.out.println("oid_oldest/host/threadName=="+oid+"/"+s+"/"+threadName);
}
Util.doUpdateTest(oid,name,conn);
conn.commit();
Хорошо, вот мой новый метод selectLockTest:
код:
public static long doSelectLockTest(String threadName) {
System.out.println("[OUTPUT FROM SELECT Lock ]...threadName=" + threadName);
PreparedStatement pst = null;
ResultSet rs = null;
Connection conn = null;
long oid = 0;
try {
String query = "SELECT * FROM table WHERE Host=? ORDER BY UpdateTime asc limit 1 FOR UPDATE";
conn = getNewConnection();
conn.setAutoCommit(false);
pst = conn.prepareStatement(query);
pst.setString(1, DbProperties.UnknownHost);
rs = pst.executeQuery();
if (rs.first()) {
String s = rs.getString("HostName");
oid = rs.getLong("OID");
//Start update then commit
if (oid != 0) {
query = "UPDATE b2bicheckpoint SET HostName=?,UpdateTimestamp=? where OID = ?";
pst = conn.prepareStatement(query);
pst.setString(1, oid + "_host_" + threadName);
pst.setLong(2, getCurrentLongTime());
pst.setLong(3, oid);
System.out.println("Select_Prestatement=" + threadName + "__" + pst);
int result = pst.executeUpdate();
conn.commit();
conn.setAutoCommit(true);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
DBUtil.close(pst);
DBUtil.close(rs);
DBUtil.close(conn);
}
return oid;
}
Результат:
[OUTPUT FROM SELECT Lock ]...threadName=Thread-1
[OUTPUT FROM SELECT Lock ]...threadName=Thread-2
Select_Prestatement=Thread-1_ : SELECT * FROM ..... FOR UPDATE
Select_Prestatement=Thread-2_: SELECT * FROM ...... FOR UPDATE
Select_Prestatement=Thread-1_: UPDATE table SET HostName='host_Thread-1' where OID = 1
Это означает, что два SELECT FOR UPDATE были (по потоку), но было выполнено только одно обновление, и хост thread_1 был сохранен. Это лучше, но это ожидаемое поведение?
Спасибо