Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于选择结果的基本锁定_Java_Sql_Sql Server_Jdbc - Fatal编程技术网

Java 基于选择结果的基本锁定

Java 基于选择结果的基本锁定,java,sql,sql-server,jdbc,Java,Sql,Sql Server,Jdbc,我有一个简单的程序,它正在修改一个数据库,这个数据库也可以由不同的用户并发运行 在这个程序中,我有几个相互依赖的顺序操作读取/更新/插入数据库 例如: String selectQuery = "select order.[total] from order where id=?"; selectQuery.setString(1, "15679"); ResultSet queryResults = selectQuery.executeQuery(); if(queryResults.n

我有一个简单的程序,它正在修改一个数据库,这个数据库也可以由不同的用户并发运行

在这个程序中,我有几个相互依赖的顺序操作读取/更新/插入数据库

例如:

String selectQuery = "select order.[total] from order where id=?";
selectQuery.setString(1, "15679");

ResultSet queryResults = selectQuery.executeQuery();

if(queryResults.next() == false){

    //execute insert into the order table
    String insertQuery = "insert into order (id, total) values (?,?)";
    .......

}
在上面的示例中,无法保证两个程序不会同时尝试插入订单,因为它们都可能执行select,获得一个空结果集,然后尝试插入

我理解在这个示例中这有点不现实,因为我们可以在
id
列上强制唯一性,这将阻止重复项被插入


我想做的是确保我们可以避免这种情况而不锁定整个表?因此,我们可以保证在执行select查询之前,我们可以知道行上不会有插入/更新/读取(可能存在也可能不存在)。之后,我们可以释放该行上的锁。

好吧,您似乎了解竞争条件以及不想在应用程序中执行检查的原因

因此,请确保
id
订单中是唯一的:

alter table orders add constraint unq_orders_id unique (id);

您可以尝试任意多的并发插入。因为数据库正在确保关系完整性,所以除一个之外,所有操作都将失败。

在SQL Server中执行此操作的正确方法是使用事务,并将
(updlock,holdlock)
提示添加到select
updlock
强制SELECT查询使用限制性更新(U)锁,而不是使用版本化快照和无锁或许可共享(S)锁。并且
updlock
像在可序列化隔离级别中一样启用范围锁定,这样即使范围中当前没有行,查询所针对的键范围也会被锁定

这将在id上放置U范围锁,防止另一个会话在键值上放置U或X锁,范围锁将锁定空的键值范围,因此无论是否存在具有该
id的任何行
。例如:

con.setAutoCommit(false);
String selectQuery = "select order.[total] from order with (updlock,holdlock) where id=?";
selectQuery.setString(1, "15679");

ResultSet queryResults = selectQuery.executeQuery();

if(queryResults.next() == false){

    //execute insert into the order table
    String insertQuery = "insert into order (id, total) values (?,?)";
    .......

}
con.commit();

完成同样事情的一种低级方法是强制事务进入可序列化隔离级别。但这不会强制在初始读取时使用U锁,因此当两个会话都运行第一个查询时,一个将成功插入,另一个将失败并出现死锁

我想我本可以把这个问题写得更好。我的问题是,我希望程序根据SELECT语句执行代码,同时保证SELECT语句的结果在程序代码执行期间不会更改。这不一定只是一个插入的东西,它只是一个例子。完美!这也适用于不基于键值的SELECT语句吗?它会对SELECT查询读取的任何内容设置限制性锁,因此是的,但锁定不会那么精细。您能否详细说明一下锁定是否不那么精细?如果SELECT生成扫描整个表的查询计划。整张桌子都会锁上的。如果查询计划扫描索引的一部分,然后对聚集索引执行书签查找,则扫描的索引范围和所有匹配的行将最终锁定,以此类推。