急!关于jdbc并发问题: 有二个客户端先后更新oracle库上的某一条数据。因为一些原因造成第一次更新持续等

时间:2021-03-07 18:00:02
关于jdbc并发问题: 有二个客户端使用人员(用A,B来区分人员)。先后更新oracle库上的某一条数据。因为一些偶然的原因造成A 第一次更新数据的行为一直属于未提交状态。然后 B 再进行更新这条数据操作的时候,于是就造成死锁状态。B不知道是什么原因,于是他多次进行更新数据操作,于是造成大面积死锁现象。 其中我使用了struts的令牌防止刷新页面而造成的重复提交操作。但对于目前这种现象没有任何防治效果。我对jdbc进行了多次断点测试操作。发现是在执行 
objStatement = objConnection.prepareStatement(execsql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
objStatement.execute();//是在执行这一处代码的时候,就卡主了,不往下面走。
这样就造成了objStatement.close();关闭不了,Connection 也无法commit。然后
finally{}//代码块中关闭连接操作无法完成,链接池中的链接也无法释放。
从而导致了连接池中有效链接全部都非法占用。造成程序速度非常慢。
由于我是用使用jdbc访问数据库层得。暂时没有太好用的思路。跪求高手
给个思路,给个建议。万分感激。分会持续散给大家。求求大家帮帮忙。

14 个解决方案

#1


我想说第一次更新数据的行为一直属于未提交状态
为什么不控制下呢?有什么原因吗?

#2


不知道我理解你的意思对不对
如果原因是:第一次更新数据的行为一直属于未提交状态

的话
我建议你加强connection的控制
使用proxy+threadlocal,这样,在proxy关闭,这样应该不会出现共用一个连接而造成死锁

#3


还“急”?

发了个帖子,就没人影了!

#4


哈,给位大大谅解谅解。是在是家里有事情急着处理。怠慢了。在此向给位路过的大大致歉!

第一次更新数据的行为,是大批量的更新数据,这个过程一般都会是在10分钟到30分钟之间。
而且更新批量数据是放在一个大事务中然后才一起提交的。

我应该这样说明:二套程序使用的是同一个数据库。所有A用程序批量更新账户的余额。
而B是客户,他这个时候去消费。于是就出现我上面所说的情况了。
A用的程序是pb写的。而B用的程序是用java写的。 A程序无法进行优化修改。
所以我想使用jdbc 在更新数据的时候 ,如果当前数据正在处于更新状态当中,就报一个错误提示。

我当时想hibernate可能对这一种情况进行了异常处理。所以写了个例子进行测试。
发现一个很有趣的现象。我分别使用了sybase库,和oracle 分别进行测试。sybase库报出了update 异常。 而oracle 则任何异常都没有提示。
我是这样测试的:先把这条记录锁住,不提交。这样就模拟出一直未提交的情况。 sybase提示错误,而oracle就没一点错误信息提示。
另外关于 longintstring 大哥 说 的proxy+threadlocal 方法。希望longintstring  能深入一点。
我也会在继续百度和 google。

再次谢谢大家的鼎力支持,我这二天会一刻也不离电脑盘。等待拜读各位神仙的思路。
谢谢!

#5


该回复于2011-04-09 10:47:54被版主删除

#6


顶~望高手正解~

#7


项项更健康...

#8


java.util.concurrent  我查了一些资料,发现 jdk1.5版本后提供了 这个并发库。发觉里面看起来还是有很好用的api,用来处理阻塞队列,和设置超时。 目前正在写例子测试中,还不知道能不能满足我想要的结果。如果各位路过的神仙曾经有使用过这个库的经验。希望赐教,给个看法,或者一些例子什么的。给小弟一个启发。知道分少了很多。但是还是会多赚点分,继续散给大家。
另外,如果我把Connection的事务提到 TRANSACTION_REPEATABLE_READ 隔离级别,但是写了例子。也没有作用。代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Ping{
   public static void runJdbc() {
        String url="jdbc:oracle:thin:@127.0.0.1:1521:cftest";
        String user="anning";
        String password="cfsi_any_user08";
Connection objConnection = null;
    try {
Class.forName("oracle.jdbc.driver.OracleDriver");
System.out.println("chuangjian");
PreparedStatement objStatement = null;
objConnection = DriverManager.getConnection(url, user,password);
objConnection.setTransactionIsolation(objConnection.TRANSACTION_SERIALIZABLE);
String sql="UPDATE KC04 SET AKC085=? WHERE AAC001=? ";
objStatement=objConnection.prepareStatement(sql);
objStatement.setString(1, "11");
objStatement.setString(2, "1504011003658200000");
System.out.println("chuangjian0");
objStatement.execute();
System.out.println("chuangjian1");
objStatement.close();
objConnection.commit();
System.out.println("chuangjian2");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
     try {
objConnection.close();
} catch (SQLException e) {
}
}
}
    public static void main(String[] args)
    {
     runJdbc();
    }
}

#9


我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurrent 包下的 ScheduledExecutorService接口先:final ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
          Runnable pinger = new Runnable() {
            public void run() {
              System.out.println("PING!");//回滚数据,释放池连接
                ses.shutdown();
            }
        };
ses.schedule(pinger, 5, TimeUnit.SECONDS);//5 秒之后开始执行一次。
.... 一些执行sql语句代码。
ses.shutdown();
但是效果也不行。

#10


Statement, PreparedStatement 有个 setQueryTimeout 方法可以设置超时时间。

最主要的是,你那个事务要挂起二三十分钟,这势必得锁住啊!

#11


是啊,但是那一块的业务的处理,暂时目前无法处理优化。。所以 就只能通过这个笨办法去 实现。

其实,我最希望的是,有一个异常机制最好了。 向sybase库,如果sybase库要更新的这条记录,是锁住状态,那么,hibernate的异常机制,直接就报一个 update 失败的异常。

这样通过框架 就能控制异常了。  而现在 oracle 居然没一点反应,很费解

#12


衷心谢谢 ()火龙果()  大大 给出的建议。我试了。效果挺好的。比我自己这二天研究使用 jdk并发库所使用的例子强多了。  衷心感谢你 以及 各位路过的神仙大大。 小弟在此拜谢。

#13


引用 9 楼 anna527 的回复:
我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurr……

火龙果,这个一般设置为多长时间?60s怎么样?

#14


引用 9 楼 anna527 的回复:
我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurr……

刚引用错了,火龙果,这个一般设置为多长时间?60s怎么样?

#1


我想说第一次更新数据的行为一直属于未提交状态
为什么不控制下呢?有什么原因吗?

#2


不知道我理解你的意思对不对
如果原因是:第一次更新数据的行为一直属于未提交状态

的话
我建议你加强connection的控制
使用proxy+threadlocal,这样,在proxy关闭,这样应该不会出现共用一个连接而造成死锁

#3


还“急”?

发了个帖子,就没人影了!

#4


哈,给位大大谅解谅解。是在是家里有事情急着处理。怠慢了。在此向给位路过的大大致歉!

第一次更新数据的行为,是大批量的更新数据,这个过程一般都会是在10分钟到30分钟之间。
而且更新批量数据是放在一个大事务中然后才一起提交的。

我应该这样说明:二套程序使用的是同一个数据库。所有A用程序批量更新账户的余额。
而B是客户,他这个时候去消费。于是就出现我上面所说的情况了。
A用的程序是pb写的。而B用的程序是用java写的。 A程序无法进行优化修改。
所以我想使用jdbc 在更新数据的时候 ,如果当前数据正在处于更新状态当中,就报一个错误提示。

我当时想hibernate可能对这一种情况进行了异常处理。所以写了个例子进行测试。
发现一个很有趣的现象。我分别使用了sybase库,和oracle 分别进行测试。sybase库报出了update 异常。 而oracle 则任何异常都没有提示。
我是这样测试的:先把这条记录锁住,不提交。这样就模拟出一直未提交的情况。 sybase提示错误,而oracle就没一点错误信息提示。
另外关于 longintstring 大哥 说 的proxy+threadlocal 方法。希望longintstring  能深入一点。
我也会在继续百度和 google。

再次谢谢大家的鼎力支持,我这二天会一刻也不离电脑盘。等待拜读各位神仙的思路。
谢谢!

#5


该回复于2011-04-09 10:47:54被版主删除

#6


顶~望高手正解~

#7


项项更健康...

#8


java.util.concurrent  我查了一些资料,发现 jdk1.5版本后提供了 这个并发库。发觉里面看起来还是有很好用的api,用来处理阻塞队列,和设置超时。 目前正在写例子测试中,还不知道能不能满足我想要的结果。如果各位路过的神仙曾经有使用过这个库的经验。希望赐教,给个看法,或者一些例子什么的。给小弟一个启发。知道分少了很多。但是还是会多赚点分,继续散给大家。
另外,如果我把Connection的事务提到 TRANSACTION_REPEATABLE_READ 隔离级别,但是写了例子。也没有作用。代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Ping{
   public static void runJdbc() {
        String url="jdbc:oracle:thin:@127.0.0.1:1521:cftest";
        String user="anning";
        String password="cfsi_any_user08";
Connection objConnection = null;
    try {
Class.forName("oracle.jdbc.driver.OracleDriver");
System.out.println("chuangjian");
PreparedStatement objStatement = null;
objConnection = DriverManager.getConnection(url, user,password);
objConnection.setTransactionIsolation(objConnection.TRANSACTION_SERIALIZABLE);
String sql="UPDATE KC04 SET AKC085=? WHERE AAC001=? ";
objStatement=objConnection.prepareStatement(sql);
objStatement.setString(1, "11");
objStatement.setString(2, "1504011003658200000");
System.out.println("chuangjian0");
objStatement.execute();
System.out.println("chuangjian1");
objStatement.close();
objConnection.commit();
System.out.println("chuangjian2");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
     try {
objConnection.close();
} catch (SQLException e) {
}
}
}
    public static void main(String[] args)
    {
     runJdbc();
    }
}

#9


我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurrent 包下的 ScheduledExecutorService接口先:final ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
          Runnable pinger = new Runnable() {
            public void run() {
              System.out.println("PING!");//回滚数据,释放池连接
                ses.shutdown();
            }
        };
ses.schedule(pinger, 5, TimeUnit.SECONDS);//5 秒之后开始执行一次。
.... 一些执行sql语句代码。
ses.shutdown();
但是效果也不行。

#10


Statement, PreparedStatement 有个 setQueryTimeout 方法可以设置超时时间。

最主要的是,你那个事务要挂起二三十分钟,这势必得锁住啊!

#11


是啊,但是那一块的业务的处理,暂时目前无法处理优化。。所以 就只能通过这个笨办法去 实现。

其实,我最希望的是,有一个异常机制最好了。 向sybase库,如果sybase库要更新的这条记录,是锁住状态,那么,hibernate的异常机制,直接就报一个 update 失败的异常。

这样通过框架 就能控制异常了。  而现在 oracle 居然没一点反应,很费解

#12


衷心谢谢 ()火龙果()  大大 给出的建议。我试了。效果挺好的。比我自己这二天研究使用 jdk并发库所使用的例子强多了。  衷心感谢你 以及 各位路过的神仙大大。 小弟在此拜谢。

#13


引用 9 楼 anna527 的回复:
我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurr……

火龙果,这个一般设置为多长时间?60s怎么样?

#14


引用 9 楼 anna527 的回复:
我在cmd 下 用 plsql 命令连上oracle 库,然后写一个update语句,执行这条记录之后没有commit;

然后,我再执行上面的代码,发现到objStatement.execute(); 就卡主,没有往下走。

我就像达到 如果在 runJdbc方法内 执行的时间超过我设定的限制时间,那么就回滚数据并

执行关闭数据库连接。 我使用了 java.util.concurr……

刚引用错了,火龙果,这个一般设置为多长时间?60s怎么样?