JDBC-Sperren eine Zeile mit SELECT FOR UPDATE, funktioniert nicht
Ich habe Probleme mit MySQL SELECT .. FOR UPDATE, hier ist die Abfrage, die ich versuche zu laufen:
SELECT * FROM tableName WHERE HostName='UnknownHost'
ORDER BY UpdateTimestamp asc limit 1 FOR UPDATE
Danach den betreffenden thread ein UPDATE und ändern Sie den Hostnamen, die ist dann sollte es entsperren der Zeile ein.
Ich bin mit einer multi-threaded java-Anwendung, also 3 threads ausgeführt werden diese SQL-Anweisung, aber wenn thread 1 ausgeführt wird, es nicht sperren Ihre Ergebnisse von thread 2 & 3. Daher werden threads, die 2 & 3 sind immer die gleichen Ergebnisse, und Sie könnten zum aktualisieren der gleichen Zeilen.
Auch jeder thread auf seine eigenen mysql-Verbindung.
Ich verwende Innodb, mit transaction-isolation = READ-COMMITTED, und das Autocommit ausgeschaltet ist, bevor die Ausführung des select for update
kann ich da etwas verpasst? ODER gibt es vielleicht eine bessere Lösung?
Vielen Dank.
Code :
public BasicJDBCDemo()
{
Le_Thread newThread1=new Le_Thread();
Le_Thread newThread2=new Le_Thread();
newThread1.start();
newThread2.start();
}
Thread :
class Le_Thread extends Thread
{
public void run()
{
tring name = Thread.currentThread().getName();
System.out.println( name+": Debut.");
long oid=Util.doSelectLockTest(name);
Util.doUpdateTest(oid,name);
}
}
Wählen Sie :
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 Timestamp asc limit 1 FOR UPDATE";
conn=getNewConnection();
pst = conn.prepareStatement(query);
pst.setString(1, DbProperties.UnknownHost);
System.out.println("pst="+threadName+"__"+pst);
rs = pst.executeQuery();
if (rs.first())
{
String s = rs.getString("HostName");
oid = rs.getLong("OID");
System.out.println("oid_oldest/host/threadName=="+oid+"/"+s+"/"+threadName);
}
}
catch (SQLException ex)
{
ex.printStackTrace();
}
finally
{
DBUtil.close(pst);
DBUtil.close(rs);
DBUtil.close(conn);
}
return oid;
}
Bitte helfen.... :
Ergebnis :
Thread-1: Debüt. Thread-2: Debüt. [OUTPUT AUS WÄHLEN Sie Lock ]...threadName=Thread-1 Neue Verbindung.. [OUTPUT AUS WÄHLEN Sie Lock ]...threadName=Faden-2 Neue Verbindung.. pst=Thread-2: SELECT * FROM b2biCheckPoint WHERE HostName='UnknownHost' ORDER BY UpdateTimestamp asc limit 1 FOR UPDATE pst=Thread-1: SELECT * FROM b2biCheckPoint WHERE HostName='UnknownHost' ORDER BY UpdateTimestamp asc limit 1 FOR UPDATE oid_oldest/host/threadName==1/UnknownHost/Thread-2 oid_oldest/host/threadName==1/UnknownHost/Thread-1 [UPDATE durchführen] ... oid = 1, thread=Faden-2 Neue Verbindung.. [UPDATE durchführen] ... oid = 1, thread=Faden-1 pst_threadname=Thread-2: UPDATE b2bicheckpoint SET HostName='1_host_Thread-2',UpdateTimestamp=1294940161838 where OID = 1 Neue Verbindung.. pst_threadname=Thread-1: UPDATE b2bicheckpoint SET HostName='1_host_Thread-1',UpdateTimestamp=1294940161853 where OID = 1
Was meinst du damit ?
InformationsquelleAutor Rachid | 2011-01-13
Du musst angemeldet sein, um einen Kommentar abzugeben.
Du bist super-verwirrt, aber zumindest Dinge, die besser Aussehen, nachdem Sie Ihre änderungen. Es gibt mehrere Möglichkeiten, dies zu tun, aber der beste Weg den ich gefunden habe, ist tatsächlich nutzen die JDBC -
ResultSet.update*
Methoden:Zuerst müssen Sie bereiten Sie Ihre
SELECT ... FOR UPDATE
- Anweisung mit derResultSet.CONCUR_UPDATABLE
argument, wie folgt aus:Dann, Sie haben tatsächlich aktualisieren Sie die Tabelle mit ResultSet:
Dritte, werden Sie wahrscheinlich brauchen, um eine Transaktion, die ich sehen kann, in Ihrem update. Ich hoffe, dass Ihr
DbUtil.close
Methoden nicht werfen Ausnahmen, auf null prüfen, etc. Auch wenn deine Methode wird komplizierter, sollten Sie die rollback-Logik gibt es auch.Sollten Sie nicht ändern müssen, um
my.ini
aus irgendeinem Grund.InformationsquelleAutor Christopher Schultz
Die Verbindung, die Sie erstellen, wählt für das update muss die gleiche, die verwendet wird, um das update durchführen. Sonst ist es nicht Teil der gleichen Transaktion und gibt die Sperre frei, so dass Ihr andere threads starten, um es so gut ausgeführt. Also in Ihrem code, den Sie brauchen, um dies zu tun:
Könnten Sie bitte senden Sie mir Ihr Beispiel-code den ich dann vergleichen Sie es mit mir ?
Hallo Rachid, ich kann nicht teilen den code, aber ich erinnerte mich gerade, dass Sie können ändern Sie die Isolationsstufe für die Verbindung mit setTransactionIsolation. Probieren Sie es aus und sehen, ob es für Sie arbeitet.
Ich habe die meine.ini nur für Testzwecke, aber es immer noch das gleiche Verhalten, ich meine die beiden threads führen können, wählen Sie FÜR die AKTUALISIERUNG auf der gleichen Zeile, die Sie ausführen, das update zu. So zwei updates ausgeführt werden auf der gleichen Zeile! wie ich sehen kann, in der Konsole : pst_threadname=Thread2_: UPDATE b2bicheckpoint SET HostName='1_host_Thread-2',UpdateTimestamp=1294940161838 where OID = 1 pst_threadname=Thread1_: UPDATE b2bicheckpoint SET HostName='1_host_Thread-1',UpdateTimestamp=1294940161853 where OID = 1
Der commit wird die Sperre auf die Zeilen. Aber ich sah nur den Teil des Codes, der für die Aktualisierung, und es ist eine eigene Methode, so ist es Ihr problem! Sie brauchen, um passieren Ihre bereits erstellten Verbindung zu dieser Methode, anstatt ein neues zu erstellen. Ansonsten ist es, wie Sie begann eine neue Transaktion.
InformationsquelleAutor Hiro2k