java 线程和定时器造成的数据库死锁

时间:2022-12-14 00:51:00
   Java程序中有一个线程和一个定时器,他们都会对数据库中的时间进行修改操作。有时可能会对同一条数据进行操作这样就出现了线程和定时器都处在阻塞状态了 没有任何反应了。请问如何才能避免这样造成的死锁问题呢?很急!

12 个解决方案

#1


你这个是多线程了撒。定时器也是一个单独的线程,所以你在操作数据有交叉的地方应该加锁。用synchronized加同步锁。

#2


加同步锁!!

#3


这样就可以了吗?也就是在操作数据库的地方加锁?我是想说这两个线程如何对表操作都是不可定的 所以死锁的情况很容易出现!  

#4


java 线程和定时器造成的数据库死锁同步锁,相对的性能会有所降低

#5


首先 从你介绍的情况看,理论上不存在“死锁”。因为各自都是拿数据库 1个连接去执行一个操作后归还或关闭。
数据库本身是支持多线程并发访问,你所说的阻塞现象具体是什么?2个线程都在进行更新操作时等待?
如果你的代码很少,可以把代码放上来给大家分析。
同时提醒synchronized这样一种锁是满足某个条件下才可以有效的。

#6


能详细贴一下sql以及线程代码吗?具体问题还是要具体分析。

#7


首先定时器执行的是下面代码,是根据主键修改对性的seqId和sendtime:
String sql = "update tb_msg_send set seqId=?,sendTime=?"
+ " where keyNum=?";//
try {
System.out.println("update keyNum:"+keyNum);
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, seqId.trim());
psmt.setTimestamp(2, sendTime);
psmt.setString(3, keyNum.trim());
psmt.executeUpdate();
线程根据上面的seqID修改对应的msgId:
String sql = "update tb_msg_send set msgId=?" + " where seqId=?";//
try {
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, msgId.trim());
psmt.setString(2, seqId.trim());

psmt.executeUpdate();
同时线程会执行下面操作,根据上面修改好的msgId修改sendSTATE 和returntime
String sql = "update tb_msg_send set sendState=?,returnTime=?"
+ " where msgId=?";//
try {
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, sendState.trim());
psmt.setTimestamp(2, returnTime);
psmt.setString(3, msgId.trim());

psmt.executeUpdate();


需要说明的是:定时器和线程是不确定是否同时执行的,因为这两个线程一直在运行,按理说应该先执行定时器需要的操作,然后线程在按照顺序执行相应的修改。问题是这个线程什么时候进行操作时不确定的。也就是说线程要进行的操作即上面说的“ 线程根据上面的seqID修改对应的msgId:”这个操作有可能和“ 首先定时器执行的是下面代码,是根据主键修改对性的seqId和sendtime:”这个操作同时进行!所以我才怀疑是死锁的问题。反正就是在执行的时候突然程序就像停止一样没有任何反应了 本来方法中 都有sysout的输出的 但是一出现这个现象就什么都没有了!

#8


还有mysql的InnoDB是默认支持行级锁同时也支持表级锁

#9


按理不应该啊 是不应该死锁的 死锁是互相争对方占着的锁,即使双方都是获取的同一个数据库连接,但这里有吗,没有吧

能确定是停在哪一句吗

#10


引用 7 楼 w_jw_b 的回复:
con = DBUtil.getConnection();

DBUtil提供的是连接池(长连接) 还是一次性连接(短连接)?
为什么你的线程执行2个操作去拿了2次数据库连接?
建议每次在执行前输出aql语句,当发现程序停止时 直接拿输出的语句去mysql执行;看是否是数据库被锁产生的等待现象。
同时提醒mysql的InnoDB仅针对主键修改开启行级锁,其他修改默认都开启表级锁。
初步判定是你自己程序代码有问题,锁的问题应该是在数据库那边(也可能是数据库连接)。
经验啊经验~~~哎

#11


DBUtil中的getConnection方法如下使用的是Jdbc连接方式:
public static Connection getConnection() {
Connection con = null;
try {
Class.forName(driver);
con = DriverManager.getConnection(url.trim()
+ "?useUnicode=true&characterEncoding=GBK&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true", uid, pwd);
} catch (Exception e) {
...... }

return con;
}

#12


而且每次连接执行完后在finally {
closeDB();
}中将ResultSet、PreparedStatement和Connectio一次关闭了
closeDB方法代码如下:
try {
if (rs != null){
rs.close();
    rs=null;
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (psmt != null)
{
psmt.close();
psmt=null;
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (con != null){
con.close();
con=null;
}
} catch (Exception e) {
e.printStackTrace();

#1


你这个是多线程了撒。定时器也是一个单独的线程,所以你在操作数据有交叉的地方应该加锁。用synchronized加同步锁。

#2


加同步锁!!

#3


这样就可以了吗?也就是在操作数据库的地方加锁?我是想说这两个线程如何对表操作都是不可定的 所以死锁的情况很容易出现!  

#4


java 线程和定时器造成的数据库死锁同步锁,相对的性能会有所降低

#5


首先 从你介绍的情况看,理论上不存在“死锁”。因为各自都是拿数据库 1个连接去执行一个操作后归还或关闭。
数据库本身是支持多线程并发访问,你所说的阻塞现象具体是什么?2个线程都在进行更新操作时等待?
如果你的代码很少,可以把代码放上来给大家分析。
同时提醒synchronized这样一种锁是满足某个条件下才可以有效的。

#6


能详细贴一下sql以及线程代码吗?具体问题还是要具体分析。

#7


首先定时器执行的是下面代码,是根据主键修改对性的seqId和sendtime:
String sql = "update tb_msg_send set seqId=?,sendTime=?"
+ " where keyNum=?";//
try {
System.out.println("update keyNum:"+keyNum);
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, seqId.trim());
psmt.setTimestamp(2, sendTime);
psmt.setString(3, keyNum.trim());
psmt.executeUpdate();
线程根据上面的seqID修改对应的msgId:
String sql = "update tb_msg_send set msgId=?" + " where seqId=?";//
try {
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, msgId.trim());
psmt.setString(2, seqId.trim());

psmt.executeUpdate();
同时线程会执行下面操作,根据上面修改好的msgId修改sendSTATE 和returntime
String sql = "update tb_msg_send set sendState=?,returnTime=?"
+ " where msgId=?";//
try {
con = DBUtil.getConnection();
psmt = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
psmt.setString(1, sendState.trim());
psmt.setTimestamp(2, returnTime);
psmt.setString(3, msgId.trim());

psmt.executeUpdate();


需要说明的是:定时器和线程是不确定是否同时执行的,因为这两个线程一直在运行,按理说应该先执行定时器需要的操作,然后线程在按照顺序执行相应的修改。问题是这个线程什么时候进行操作时不确定的。也就是说线程要进行的操作即上面说的“ 线程根据上面的seqID修改对应的msgId:”这个操作有可能和“ 首先定时器执行的是下面代码,是根据主键修改对性的seqId和sendtime:”这个操作同时进行!所以我才怀疑是死锁的问题。反正就是在执行的时候突然程序就像停止一样没有任何反应了 本来方法中 都有sysout的输出的 但是一出现这个现象就什么都没有了!

#8


还有mysql的InnoDB是默认支持行级锁同时也支持表级锁

#9


按理不应该啊 是不应该死锁的 死锁是互相争对方占着的锁,即使双方都是获取的同一个数据库连接,但这里有吗,没有吧

能确定是停在哪一句吗

#10


引用 7 楼 w_jw_b 的回复:
con = DBUtil.getConnection();

DBUtil提供的是连接池(长连接) 还是一次性连接(短连接)?
为什么你的线程执行2个操作去拿了2次数据库连接?
建议每次在执行前输出aql语句,当发现程序停止时 直接拿输出的语句去mysql执行;看是否是数据库被锁产生的等待现象。
同时提醒mysql的InnoDB仅针对主键修改开启行级锁,其他修改默认都开启表级锁。
初步判定是你自己程序代码有问题,锁的问题应该是在数据库那边(也可能是数据库连接)。
经验啊经验~~~哎

#11


DBUtil中的getConnection方法如下使用的是Jdbc连接方式:
public static Connection getConnection() {
Connection con = null;
try {
Class.forName(driver);
con = DriverManager.getConnection(url.trim()
+ "?useUnicode=true&characterEncoding=GBK&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true", uid, pwd);
} catch (Exception e) {
...... }

return con;
}

#12


而且每次连接执行完后在finally {
closeDB();
}中将ResultSet、PreparedStatement和Connectio一次关闭了
closeDB方法代码如下:
try {
if (rs != null){
rs.close();
    rs=null;
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (psmt != null)
{
psmt.close();
psmt=null;
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (con != null){
con.close();
con=null;
}
} catch (Exception e) {
e.printStackTrace();