误用Connection.setAutoCommit导致的数据库死锁问题。
系统在发布到用户的的服务器了,运行一段时间偶尔出现某些功能不能正常运行,甚至不能自动恢复,严重导致服务器当机,表现为服务器不响应用户的请求,数据库有大量的锁。在服务器重启后才能恢复正常。今天通遍的查看了一下代码,初步分析了原因,记录了下来,跟大家交流交流。
先看下面一段有问题的代码:
1 Connection con = null;
2 try{
3 con = getConnection();
4 con.setAutoCommit(false);
/*
5 * update USER set name=’winson’ where id=’000001’;
*/
6 con.commit();
7 }finally{
8 if(con!=null){
9 try {
10 con.close();
11 } catch (SQLException e) {
12 e.printStackTrace();
13 }
}
}
分析:问题就出现在第4行,写代码的人把数据库连接con 设置成非自动提交,但没有在执行出现异常的时候进行回滚。如果在执行第5行的时候出现异常,con既没有提交也没有回滚,表USER就会被锁住(如果oracle数据库就是行锁),而这个锁却没有机会释放。有人会质疑,在执行con.close()的时候不会释放锁吗?因为如果应用服务器使用了数据库连接池,连接不会被断开。
附:在oracle上查看锁的方法:select * from v$lock_object或者select * from v$lock.
JDBC的api文档是这样对setAutoCommit方法解释的:
Sets the connection's auto-commit mode to enableAutoCommit
.
Newly created Connection
objects are in auto-commit mode by default, which means that individual SQL statements are committed automatically when the statement is completed. To be able to group SQL statements into transactions and commit them or roll them back as a unit, auto-commit must be disabled by calling the method setAutoCommit
with false
as its argument. When auto-commit is disabled, the user must call either the commit
or rollback
method explicitly to end a transaction.(一定不能大意哦,如果设置成非自动提交,在最后一定要调用commit或者rollback方法)
The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet
object, the statement completes when the last row of the result set has been retrieved or the ResultSet
object has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In this case, the commit may occur when all results and output parameter values have been retrieved, or the commit may occur after each result is retrieved.
参考正确的写法应该是:
Connection con = null;
try{
con = getConnection();
con.setAutoCommit(false);
/*
* do what you want here.
*/
con.commit();
}catch(Throwable e){
if(con!=null){
try {
con.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
throw new RuntimeException(e);
}finally{
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
这种疏忽很容易出现,但又导致非常严重的运行问题。所以在这里作个提醒,以后在处理外部资源的时候一定要格外小心。今天还发现代码中一些地方滥用synchronized关键字,导致系统性能受到很大的影响,处理不当跟前面提到问题一起出现,那系统就是时候over了。
另外,如果不是自己来处理事务,可能在用hibernate或者ejb等,都一定要记住在处理完之后要提交或者回滚哦。
如果你有任何意见或者有补充,请不要吝啬的在乎你的笔墨。
分享到:
- 2007-02-04 00:18
- 浏览 4078
- 评论(0)
- 论坛回复 / 浏览 (0 / 5993)
- 查看更多
相关推荐
`AreaAdd1`可能包含了`try-catch`块,对可能出现的数据库连接问题、SQL执行失败等问题进行处理。 6. **关闭资源**: 执行完数据库操作后,需要关闭打开的资源如`ResultSet`、`Statement`和`Connection`,以避免资源...
本文将详细介绍一个用于连接MySQL数据库的Java类——`JDBCconnection.java`。该类实现了通过Java Database Connectivity (JDBC) 连接到名为 `test` 的MySQL数据库,并能够执行基本的数据库操作,如创建连接、执行...
在JDBC中,我们可以调用Connection对象的setAutoCommit(false)来关闭自动提交,然后在转账操作结束后,根据结果决定是否调用commit()或rollback()。 5. **错误处理与资源释放**:在完成数据库操作后,必须释放所有...
Java.sql.Connection 接口是Java数据库连接(JDBC)的一部分,它是应用程序与数据库之间建立通信的桥梁。在Java编程中,当你需要执行SQL语句、管理事务或者获取数据库元数据时,都会用到Connection对象。以下是对...
在Java中,可以通过Connection对象的setAutoCommit()方法关闭自动提交,然后手动调用commit()或rollback()来控制事务的提交和回滚。例如: ```java connection.setAutoCommit(false); try { // 执行数据库操作 ...
例如,使用`Class.forName()`加载数据库驱动,通过`DriverManager.getConnection()`获取数据库连接,`Statement`或`PreparedStatement`对象来执行SQL,最后使用`Connection.close()`关闭连接。 其次,事务是数据库...
当调用`DriverManager.getConnection()`方法时,`DriverManager`会从已经加载的驱动程序池中找到与指定数据库URL相匹配的驱动程序,进而建立数据库连接。 #### 二、加载不同类型的JDBC驱动程序 在使用JDBC连接...
在Java EE(企业版)开发中,数据库连接是不可或缺的一部分,尤其是在构建Web应用...在实际开发中,还需要注意异常处理、数据库性能优化、安全性等方面的问题。学习和熟练掌握这些技能对于Java EE开发者来说至关重要。
SQLite JDBC是Java应用程序连接SQLite数据库的一种方式,它允许开发者通过标准的JDBC接口与SQLite数据库进行交互。SQLite是一个轻量级、嵌入式、零配置的SQL数据库引擎,广泛应用于移动设备、桌面应用以及Web应用中...
例如,Java中的`Connection.setAutoCommit(false)`可以禁用自动提交,然后通过`Connection.commit()`或`Connection.rollback()`手动控制事务。 8. **预编译语句(PreparedStatement)**:预编译语句可以提高性能,...
`Connection.setAutoCommit(false)`关闭自动提交,`Connection.commit()`提交事务,`Connection.rollback()`回滚事务。 7. 连接池 在实际应用中,为了提高性能和资源利用率,通常会使用连接池(如C3P0、HikariCP、...
3. **数据库连接(Connection)**:Java程序通过连接对象与数据库建立联系,执行SQL语句并获取结果。 4. **Statement/PreparedStatement/CallableStatement**:用于执行SQL语句的接口,Statement用于简单查询,...
JDBC支持事务处理,通过`Connection.setAutoCommit(false)`来手动开启事务,然后通过`Connection.commit()`或`Connection.rollback()`来提交或回滚事务。 7. **数据库元数据(DatabaseMetaData)**: `Connection...
connection.setAutoCommit(false/true); 2. 提交事务 connection.commit(); 3. 回滚 connection.rollback(); - 实现转账: 超人 500 蝙蝠侠 5000 蝙蝠侠给超人转2000 执行第一次成功 执行第二次成功 执行第三...
例如,使用`Connection.setAutoCommit(false)`开启手动事务控制,`Connection.commit()`和`Connection.rollback()`来提交或回滚事务。批处理通过`Statement.addBatch()`和`Statement.executeBatch()`提升性能。而...
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; public class TransactionExample { public static void main(String[] args) { String url = "jdbc:mysql://...
1. 开启事务:`Connection.setAutoCommit(false)` 2. 提交事务:`Connection.commit()` 3. 回滚事务:`Connection.rollback()` 4. 设置隔离级别:`Connection.setTransactionIsolation(int level)`,常见的级别有...
例如,使用`Connection.setAutoCommit(false)`开启手动提交事务,然后在所有插入完成后调用`Connection.commit()`。 6. **数据库优化**:检查数据库配置,如索引、缓存设置和并发控制,确保数据库能够快速处理大量...
例如,使用`connection.setAutoCommit(false)`关闭自动提交,然后在所有操作成功后调用`connection.commit()`提交事务,否则调用`connection.rollback()`回滚。 9. **安全性**:确保对用户输入进行验证和清理,避免...