Mysql строка блокировки SELECT Java JDBC [дубликат]

  1. PInvoke для вызова Win32 API SetSystemTime, ( example )
  2. . Классы System.Management с классом WMI Win32_OperatingSystem и вызовом SetDateTime в этом классе.
  3. Оба требуют, чтобы вызывающему было предоставлено SeSystemTimePrivilege и эта привилегия включена.

7
задан Luke Woodward 13 January 2011 в 21:53
поделиться

3 ответа

Вы очень смущены, но, по крайней мере, все выглядит лучше после ваших изменений. Существует несколько способов сделать это, но лучший способ, который я нашел, - фактически использовать методы 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.

9
ответ дан Christopher Schultz 19 August 2018 в 02:40
поделиться

Соединение, которое вы создаете, выбирающее для обновления, должно быть таким же, как и для обновления. В противном случае он не является частью одной и той же транзакции и освобождает блокировку, поэтому ваши другие потоки начинают ее выполнять. Поэтому в вашем коде вам нужно сделать это:

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();
1
ответ дан Hiro2k 19 August 2018 в 02:40
поделиться
  • 1
    Привет Hiro2k, спасибо за ваш ответ. Я не могу изменить конфигурацию сервера базы данных, я имею в виду, что я не могу изменить файл my.ini. Но в руководстве MySQL они говорят, что если READ-COMMITTED установлен, только индекс будет заблокирован, что нормально в моем случае, потому что столбец HostName является индексом .... – Rachid 13 January 2011 в 18:27
  • 2
    Не могли бы вы отправить мне свой примерный код, а затем сравнить его с моим? – Rachid 13 January 2011 в 18:30
  • 3
    Привет, Rachid, я не могу поделиться этим кодом, но я просто вспомнил, что вы можете изменить уровень изоляции на соединение, используя setTransactionIsolation. Попробуйте и посмотрите, работает ли это для вас. – Hiro2k 13 January 2011 в 18:40
  • 4
    Я изменил my.ini только для тестирования, но все равно такое же поведение, я имею в виду, что обе потоки могут запускать выбор FOR UPDATE в той же строке, что и они выполняют обновление. Таким образом, два обновления выполняются в одной строке! как я могу видеть на консоли: pst_threadname = Thread2_: UPDATE b2bicheckpoint SET HostName = '1_host_Thread-2', UpdateTimestamp = 1294940161838 где OID = 1 pst_threadname = Thread1_: UPDATE b2bicheckpoint SET HostName = '1_host_Thread-1', UpdateTimestamp = 1294940161853 где OID = 1 – Rachid 13 January 2011 в 18:48
  • 5
    Конец освобождает блокировку вашей строки. Однако я только что видел часть вашего кода, которая делает обновление, и она находится в собственном методе, поэтому есть ваша проблема! Вам необходимо передать уже созданное соединение этому методу вместо создания нового. В противном случае это похоже на то, что вы начали новую транзакцию. – Hiro2k 13 January 2011 в 19:55

Хорошо, вот мой новый метод 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 был сохранен. Это лучше, но это ожидаемое поведение?

Спасибо

0
ответ дан OldCurmudgeon 19 August 2018 в 02:40
поделиться
  • 1
    вы не должны задавать дополнительные вопросы в форме ответа. – törzsmókus 13 March 2013 в 12:50
Другие вопросы по тегам:

Похожие вопросы: