2011-02-25 68 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