oracle exists并发
前些天仔细研究了下oracle exists与in的区别。经过深层次的分析后发现exists与in并不能互用。
先谢谢@Elvis_dataguru文章的详细解说,我基于他基础上做详细分析后总结如下:
-
exists的解释:“Exists只能用于子查询,若匹配到一条结果,子查询中断,并将条件标志为true”。
-
in的解释“in不管匹配到匹配不到都全部匹配完毕”。
此文并非比较exists与in的区别,或者讨论两者的效率,或者两者互用的注意事项,此类文章在百度、google上都有很多解释。而正如@Elvis_dataguru,大家都认为exists与in能够在一定程度上互用。
以下是我分析的过程:
-
数据表结构(n条数据)
table user ( userNo varchar2(10) not null, userType varchar2(1) not null )
-
操作语句
操作语句1
操作语句2update user t set t.userType = $USER_TYPE_NEW$ where t.userType <> $USER_TYPE_OLD$
update user t set t.userType = $USER_TYPE_NEW$ where exists(select 1 from user tt where tt.userType <> $USER_TYPE_OLD$)
sql语句说明:如果userType不是USER_TYPE_OLD则更新为USER_TYPE_NEW。以上是我分别测试的两个sql语句。两个sql语句最终目的是一样的。
-
操作代码
java代码说明:传入修改的内容。USER_TYPE_NEW对应sql中$USER_TYPE_NEW$参数,USER_TYPE_OLD对应sql中$USER_TYPE_OLD$参数。先启动两个线程,分别调用Test2执行sql语句。将update影响的行数返回,分别是i和j。如果i和j都不等于0,则将数据还原继续循环执行。for (;;) { Map<String, Integer> map1 = new HashMap<String, Integer>(); map1.put("USER_TYPE_NEW", 2);//修改成的参数(new的参数) map1.put("USER_TYPE_OLD", 1);//old的参数 Thread t1 = new Thread(new Test2(map1)); Map<String, Integer> map2 = new HashMap<String, Integer>(); map2.put("USER_TYPE_NEW", 1);//修改成的参数(new的参数) map2.put("USER_TYPE_OLD", 2);//old的参数 Thread t2 = new Thread(new Test2(map2)); t1.start(); t2.start(); t1.join(); t2.join(); int i = map1.get("SUM_COUNT");// 更新的条数 int j = map2.get("SUM_COUNT");// 更新的条数 System.out.println("MAP1(2,1) 的值是:" + i); System.out.println("MAP2(1,2) 的值是:" + j); if (i != 0 && j != 0) { // 如果更新条数有一个不为0。则将数据还原后继续执行。 Map<String, Integer> map3 = new HashMap<String, Integer>(); map3.put("USER_TYPE_NEW", 0);//原始值 map3.put("USER_TYPE_OLD", 3);//其他确定不等于的任意值 Thread t3 = new Thread(new Test2(map3)); t3.start(); t3.join(); } else { // 如果更新条数一样。将直接结束循环。 break; } }
-
操作结果
操作语句1执行结果:在应用开始执行后一直执行下去(跑一晚上,执行次数未知,语句1写的是“<>”,我同样测试过了“in”的情况,结果是一样的,不分开说明了)。i等于0或者n。j等于n或者0。当i等于0时,j等于n;当i等于n时,j等于0。
操作语句2执行结果:在应用开始执行后10秒左右后(执行几十次的平均值)。i等于n,j同时也等于n,跳出for循环后服务停止运行。
以上总结:
1.in在oracle内处理了并发,而exists在一定并发下存在问题。可能正是因为exists只检查是否有记录后返回true的缘故,此问题我查阅了大量的oracle文献也未得到相关的说明。
2.exists子句前面的update和后面的子查询分开执行,在oracle执行exists子句后,update时将不再判断exists子句是否为真。此结果可以从执行操作语句2时i和j的值相等得来(如果会判断,结果应该是i + j = n)。