Java 锁定数据库行的简单方法
我遇到了一些遗留代码,它们应该在Java 锁定数据库行的简单方法,java,database,locking,record,Java,Database,Locking,Record,我遇到了一些遗留代码,它们应该在序列表中保留递增的序列号。此序列号将用作另一个表(订单表)中新记录的ID 我认为它应该做的是: 如果有此序列的记录,则获取该值并返回该数字+1 如果没有记录,则扫描实际表格以找到当前最大值,将其四舍五入到最接近的1000,并将该最大值记录在序列表格中 代码如下: private static final long SEQUENCE_BLOCK_SIZE = 1000; private static final String ID_FIELD_NAME = "Ord
序列表中保留递增的序列号。此序列号将用作另一个表(订单表)中新记录的ID
我认为它应该做的是:
如果有此序列的记录,则获取该值并返回该数字+1
如果没有记录,则扫描实际表格以找到当前最大值,将其四舍五入到最接近的1000,并将该最大值记录在序列
表格中李>
代码如下:
private static final long SEQUENCE_BLOCK_SIZE = 1000;
private static final String ID_FIELD_NAME = "Order_ID";
private static final String TABLE_NAME = "Orders";
private static long lastID = 0;
String init = null;
public long newID() throws Exception {
Connection c = null;
long id = 0;
try {
c = Connections.getConnection(init);
id = nextID(c);
} catch(Exception e) {
try {
c.close();
} catch(Exception ignore) {
}
throw e;
} finally {
if ( c != null ) {
Connections.putConnection(c);
}
}
return id;
}
/**
* Returns a new unique id for the account.
*/
protected static synchronized long nextID(Connection c) throws Exception {
// Only update the table occasionally.
if(lastID % SEQUENCE_BLOCK_SIZE == 0) {
Statement s = null;
ResultSet r = null;
try {
lastID = 0;
s = c.createStatement();
// Lock the row. +++ EH??? +++
s.executeUpdate("UPDATE sequences SET sequence_value=sequence_value WHERE sequence_name='" + ID_FIELD_NAME + "'");
// Get the current value.
r = s.executeQuery("SELECT sequence_value FROM sequences WHERE sequence_name='" + ID_FIELD_NAME + "'");
if(r.next()) {
lastID = r.getLong(1);
}
r.close();
s.close();
if(lastID == 0) {
// Get the current max value from the table.
s = c.createStatement();
r = s.executeQuery("SELECT MAX(" + ID_FIELD_NAME + ") FROM " + TABLE_NAME + "");
if(r.next()) {
lastID = ((r.getLong(1) + SEQUENCE_BLOCK_SIZE) / SEQUENCE_BLOCK_SIZE) * SEQUENCE_BLOCK_SIZE;
}
r.close();
s.close();
// Insert the new row.
s = c.createStatement();
s.executeUpdate("INSERT INTO sequences(sequence_value,sequence_name) VALUES(" + (lastID + SEQUENCE_BLOCK_SIZE) + ",'" + ID_FIELD_NAME + "')");
s.close();
}else {
// Update the row.
s = c.createStatement();
s.executeUpdate("UPDATE sequences SET sequence_value=" + (lastID + SEQUENCE_BLOCK_SIZE) + " WHERE sequence_name='" + ID_FIELD_NAME + "'");
s.close();
}
} catch(Exception e) {
throw e;
} finally {
try {
r.close();
} catch(Exception e) {
}
try {
s.close();
} catch(Exception e) {
}
}
}
return lastID++;
}
我的问题是,当序列
表中没有记录时,它不会添加新记录,尽管它正在执行插入
。我已经分别测试了插入
,它似乎工作正常。我相信这与//锁定行
语句有关。我找不到任何文档表明该语句确实会锁定该行,甚至不会产生什么效果
我正在针对SQLServer2008进行测试,但同样的机制应该适用于2000+和Oracle
针对评论添加了
我同意,对于唯一的序列号,使用本机数据库机制会更好/更有效。不幸的是,这个应用程序被设计用来驱动六个不同的数据库系统中的任何一个,当然这两个系统都可以,所以坚持使用这种技术会更好
我们在自动提交模式下运行会话。为什么插入的没有创建新记录?这与试图锁定有关吗?为什么不使用选择…进行更新*struct 问题是我没有参加交易。我在autocommit
模式下运行会话是错误的
记录锁的作用正如@Sérgio在其评论中所说。在Oracle中,update语句将锁定记录以更新其他会话,但所有尝试查询该值的会话都将检索更新前的信息。请删除代码并使用本机序列器。数据库提供它们是有原因的。你能给我一个参考吗?我可以对Oracle和SQL使用相同的代码吗?@SérgioMichels锁能保持多久/什么会导致锁被释放?@Paul我没有书面参考。这是我在数据库类中记得的。锁定将一直保持,直到您在该会话上使用提交。同样,如果其他会话选择最大值,它将返回旧值,直到会话提交更改。我同意Ineradial的观点,最好使用本地序列。你真的想以此作为我问题的答案吗?