2011-02-25 59 views
1

我有一個關於數據庫事務的問題,我不確定我的理解是否正確。我想在Java應用程序中實現用戶登錄。由於可能有多個服務器在同一個數據庫上運行,並且每個用戶只能登錄其中一個服務器,所以如果用戶已經登錄,數據庫必須存儲一個標誌。實現用戶登錄,JDBC Transactions問題

因此,假設下列表結構:

如果他沒有登錄
ID | User | PWD | Server 

其中Server是參照其中用戶在其登錄服務器,或NULL

當,我得先檢查服務器是否值是一個用戶登錄NULL,如果不是,則將其設置爲對應參考值。但是,在用戶登錄另一臺服務器的這兩條語句之間發生了什麼?交易可以檢測到這種情況嗎?例如(僞)

conn.setAutoCommit(false); 
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM users WHERE user = 'usr' AND password = 'pwd'"); 
if (rs.next()) { 
    rs.getInt("Server"); 
    if (rs.wasNull()) { 
    // Not logged in 
    conn.createStatement().execute("UPDATE users SET server = 123 WHERE user = 'usr' AND password = 'pwd'"); 
    conn.commit(); 
    } 
} else { 
    // Usr/Pwd wrong 
} 
conn.rollback(); 

如果用戶在另一臺服務器上的select和update語句之間登錄,會發生什麼?由於在交易過程中表被其他人更改了表單,或者表單執行失敗了,提交失敗了嗎?

我應該更好地使用像

UPDATE users SET server = 123 WHERE user = 'usr' AND pwd = 'pwd' AND server IS NULL 

的方法,並檢查0行受到影響?如果是這樣,我必須檢查用戶是否存在於查詢中。

使用INSERT註冊新用戶時出現類似問題。應該使用事務方法,還是將用戶列聲明爲UNIQUE並捕獲SQL異常?

回答

2

使用您的僞代碼建議使用事務將解決此問題,但一定要將事務隔離級別設置爲TRANSACTION_REPEATABLE_READ。有關詳細信息,請參閱此tutorial

您還需要abount認爲:

  • 永遠,永遠,永遠保存明文密碼數據庫。你需要使用單向散列。此外,請務必注意散列算法和實現。搜索「HBGary」和「Anonymous」來閱讀關於如果您不知道可能會發生什麼的問題。
  • 想想如果用戶登錄到一臺服務器會發生什麼,並且客戶端在他有機會註銷之前崩潰。
+0

感謝您的鏈接。當然,我不會存儲純文本PWD ...用於處理崩潰:服務器檢測套接字連接何時關閉,因此可以在此時註銷用戶。 – 2011-02-25 15:34:25

+0

太棒了,只是覺得我會提到它是安全的。 – 2011-02-25 15:37:16

0

在更新用戶行的情況下,可以指定鎖定該特定行,以便其他jdbc連接無法修改該行。

+0

你如何顯式地鎖定JDBC中的一行? – 2011-02-25 15:20:20

+0

select ... for update – xxtommoxx 2011-02-25 16:25:18

+0

好的,這和TRANSACTION_REPEATABLE_READ基本上是一樣的。我認爲設置隔離級別更清潔,因爲這樣您就不需要單獨的查詢,這取決於您是否將在稍後進行更新。只要決定你感到舒適的隔離級別即可。SQL標準並不是免費提供的,但PostgreSQL文檔指出:「儘管FOR UPDATE出現在SQL標準中,但該標準只允許它作爲DECLARE CURSOR的選項,PostgreSQL允許它在任何SELECT查詢和子查詢中使用,選擇,但這是一個擴展。「 – 2011-02-25 19:21:47