`
ygsilence
  • 浏览: 336699 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Connection.setAutoCommit使用的注意事项

    博客分类:
  • java
阅读更多


setAutoCommit总的来说就是保持数据的完整性,一个系统的更新操作可能要涉及多张表,需多个SQL语句进行操作

循环里连续的进行插入操作,如果你在开始时设置了:conn.setAutoCommit(false);
最后才进行conn.commit(),这样你即使插入的时候报错,修改的内容也不会提交到数据库,
而如果你没有手动的进行setAutoCommit(false);
出错时就会造成,前几条插入,后几条没有
会形成脏数据~~

setAutoCommit(false)的误用
(设定setAutoCommit(false)没有在catch中进行Connection的rollBack操作,操作的表就会被锁住,造成数据库死锁):
误用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等,都一定要记住在处理完之后要提交或者回滚哦。

 

例子:

import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * 用于JDBC操作数据库的公共类
 */
public class CommonSql {
    /** 数据库连接对象 */
 private Connection conn;
 /** 数据库操作对象 */
 private PreparedStatement ps;
 /** 返回的数据结果集对象 */
 private ResultSet rs;

 /**
  * 测试数据库连接是否成功
  * @param args
  */
 /**
  * 打开数据库连接并创建数据库连接对象
  * @return boolean true:连接成功,false:连接失败
  */
 public boolean openConn() {
  Boolean isPassed = false;
  String driver = RWProperties.getProperty("driver", "com/test/config/db.properties");
  String url = RWProperties.getProperty("url", "com/test/config/db.properties");
  String user = RWProperties.getProperty("user", "com/test/config/db.properties");
  String pwd = RWProperties.getProperty("pwd", "com/test/config/db.properties");

  try {
   Class.forName(driver);
   conn = DriverManager.getConnection(url, user, pwd);
   isPassed = true;
  } catch (ClassNotFoundException e) {
   closeAll();
   e.printStackTrace();
   System.out.println("数据库连接失败!");
  } catch (Exception e) {
   closeAll();
   e.printStackTrace();
   System.out.println("数据库连接失败!");
  }

  return isPassed;
 }
 /**
  * 执行数据库的新增和修改语句,只操作一张表
  * @param sql 要执行的SQL语句
  * @return boolean true:执行成功,false:执行失败
  */
 /**
     * 执行数据库的新增和修改语句,同时操作多张表
     * @param sql 要执行的SQL语句的字符串数组
     * @return boolean true:执行成功,false:执行失败
     */
 public boolean execUpdate(String[] sql) {
  boolean isPassed = false;
  // 判断连接数据库是否成功
  if (openConn()) {
   try {
    conn.setAutoCommit(false);
    for (int i = 0; i < sql.length; i++) {
     ps = conn.prepareStatement(sql[i]);
     ps.executeUpdate();
    }
    conn.commit();
    isPassed = true;
   } catch (SQLException e) {
    try {
     conn.rollback();
    } catch (SQLException e1) {
     e1.printStackTrace();
    }
    for (int i = 0; i < sql.length; i++) {
     System.out.println("SQL:"+sql[i]);
    }
    e.printStackTrace();
   } finally {
    closeAll();
   }
  } else {
   closeAll();
   for (int i = 0; i < sql.length; i++) {
    System.out.println(sql[i]);
   }
   System.out.println("数据库连接失败!");
  }

  return isPassed;
 }
    /**
     * 执行数据库的新增和修改语句,同时操作多张表
     * @param sql 要执行的SQL语句的集合
     * @return boolean true:执行成功,false:执行失败
     */
 public boolean execUpdate(List<String> sql) {
  boolean isPassed = false;
  // 判断连接数据库是否成功
  if (openConn()) {
   try {
    conn.setAutoCommit(false);
    for (int i = 0; i < sql.size(); i++) {
     ps = conn.prepareStatement(sql.get(i));
     ps.executeUpdate();
    }
    conn.commit();
    isPassed = true;
   } catch (SQLException e) {
    try {
     conn.rollback();
    } catch (SQLException e1) {
     e1.printStackTrace();
    }
    for (int i = 0; i < sql.size(); i++) {
     System.out.println("SQL:"+sql.get(i));
    }
    e.printStackTrace();
   } finally {
    closeAll();
   }
  } else {
   closeAll();
   for (int i = 0; i < sql.size(); i++) {
    System.out.println(sql.get(i));
   }
   System.out.println("数据库连接失败!");
  }

  return isPassed;
 }
    /**
     * 执行数据库查询操作
     * @param sql 要执行的SQL语句
     * @return ResultSet 返回查询的结果集对象
     */
 public ResultSet execQuery(String sql) {
     rs = null;
     // 判断连接数据库是否成功
  if (openConn()) {
   try {
    ps = conn.prepareStatement(sql);
    rs = ps.executeQuery();
   } catch (SQLException e) {
    closeAll();
    System.out.println("SQL:"+sql);
    e.printStackTrace();
   }
  } else {
   closeAll();
   System.out.println("SQL:"+sql);
   System.out.println("数据库连接失败!");
  }

  return rs;
 }
 /**
  * 关闭所有数据库连接对象
  */
 public void closeAll() {
  if (conn != null) {
   try {
    conn.close();
    conn = null;
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
  if (ps != null) {
   try {
    ps.close();
    ps = null;
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
  if (rs != null) {
   try {
    rs.close();
    rs = null;
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
 }
}


分享到:
评论
1 楼 327764984 2017-01-20  
CommonSql里
不知道把PreparedStatment和ResultSet作为实例属性保存的意义何在 它们既没有被复用 也没有被管理销毁 却在一次查询后一度持有引用阻止被GC
从生命周期角度 ResultSet短于PreparedStatment短于Connection 全部关闭操作也不是按这个顺序

相关推荐

    JavaBean中使用JDBC方式进行事务处理

    通过以上介绍,我们可以了解到在JavaBean中使用JDBC进行事务处理的具体步骤以及注意事项。合理地使用事务处理可以极大地提高应用程序的稳定性和安全性。在实际开发中,开发者应该根据具体的业务需求选择合适的事务...

    JDBC使用MySQL处理大数据+事务控制管理.txt

    **注意事项:** 1. **参数设置**:如果使用批处理仍然感觉较慢,可以通过设置`rewriteBatchedStatements=true`参数来优化性能。具体做法是在数据库连接URL中添加该参数: ```java String dbUrl = "jdbc:mysql://...

    一个关于更新Oracle中Blob问题

    - 接着,可能有一个事务管理部分,确保更新操作的原子性,例如使用`Connection.setAutoCommit(false)`和`Connection.commit()`。 4. 注意事项: - Blob数据的处理可能涉及大量的内存,因此要谨慎处理输入流,避免...

    mysql的java类库

    6. **安全注意事项**: 在实际应用中,应避免在代码中硬编码数据库凭证,可以使用环境变量、配置文件或更安全的方式管理这些敏感信息。 7. **事务处理**: MySQL Connector/J支持事务处理,通过调用`Connection....

    Oracle addBatch()用法实例详解

    5. **注意事项** - 在批量处理中,所有SQL语句应具有相同的基本结构,例如都是插入、更新或删除,且参数数量和类型一致。 - 为避免内存溢出,根据实际情况控制批处理的大小,不宜过大。 - 使用完批量操作后,记得...

    mysql-connector-java-8.0.19.zip

    8. **安全注意事项**:为了安全,应避免在代码中硬编码数据库凭据,而是从环境变量、配置文件或密钥存储中获取。此外,定期更新驱动程序以获取最新的安全补丁也至关重要。 9. **性能优化**:可以配置连接参数,如`...

    servlet jsp jdbc实验.docx

    **注意事项**: - 驱动类名应根据实际使用的数据库类型进行调整,本例中使用的是MySQL的JDBC驱动。 - `getConnection()`方法中设置了自动提交为`false`,这有利于事务的管理。 2. **测试连接**: ```java ...

    mysql-connector-java-5.1.30-bin.zip

    8. **安全注意事项**: - 避免在代码中硬编码数据库凭证,可以使用环境变量或配置文件。 - 使用预编译的`PreparedStatement`防止SQL注入攻击。 - 及时关闭数据库连接,避免资源浪费。 9. **性能优化**: - 使用...

    JavaWeb项目:JDBC02

    在"Task01"这个子项目中,你可能会实践上述JDBC操作,逐步理解并掌握它们的用法和注意事项。通过实际编写代码,你会对Java如何与数据库进行交互有更深入的理解。在实践中遇到问题时,查阅官方文档和相关教程,或者...

    JDBC学习笔记

    - 使用`Connection.setAutoCommit(false)`关闭自动提交。 - 执行一系列数据库操作。 - 成功后调用`Connection.commit()`提交事务。 - 出错时调用`Connection.rollback()`回滚事务。 #### 十五、事务的保存点...

    JDBC事务控制--讲述如何控制JDBC事务

    #### 四、注意事项 - 在实际应用中,不同的数据库可能支持的事务隔离级别不同,因此在编写代码时应考虑到这一点。 - 设置较低的隔离级别可以提高性能,但可能会导致数据不一致的问题;相反,设置较高的隔离级别可以...

    java操作Access.mdb数据库的实现.pdf

    #### 五、注意事项 - **驱动兼容性问题**:不同的JDK版本可能需要使用不同的ODBC驱动类名。 - **连接字符串**:确保连接字符串中的驱动名和数据库路径正确无误。 - **资源管理**:记得关闭所有打开的资源(如`...

    达梦的数据库连接驱动.zip

    10. **注意事项**: 使用达梦JDBC驱动时,确保你的Java环境与驱动版本兼容,同时注意数据库的连接字符串格式、用户名和密码的正确性。 通过以上介绍,你可以了解到如何在Java应用中使用达梦数据库的JDBC驱动进行...

    使用JDBC的批处理功能

    五、注意事项 1. 适当设置批处理大小:根据数据库和应用需求调整批处理中SQL语句的数量,过大可能导致内存问题,过小则无法充分利用批处理的优势。 2. 错误处理:如果批处理中某个语句失败,可以捕获...

    Java实现的mysql事务处理操作示例

    本文主要介绍了Java实现的mysql事务处理操作,结合实例形式较为详细的分析了Java基于JDBC操作mysql数据库实现事务处理的相关概念、操作技巧与注意事项。 事务处理是数据库操作的一个执行单元,它是一组要么同时执行...

    DB2 jar包和连接DB2数据库代码

    4. **使用注意事项**:在实际使用中,确保JDBC驱动的版本与DB2数据库服务器版本兼容。同时,为了保证代码的健壮性,应该捕获并处理可能抛出的异常,如`SQLException`。 5. **事务管理**:在与DB2交互时,可能需要...

    数据库连接大全

    在“数据库连接大全”这个主题中,我们将会深入探讨如何在JSP中建立与各种数据库的连接,以及相关的最佳实践和注意事项。 1. **JDBC (Java Database Connectivity)** JDBC是Java平台上的标准接口,它允许Java程序...

    JDBC经典练习题

    通过上述JDBC的经典练习,可以深入理解数据库操作的基本流程和注意事项,为后续的数据库开发工作打下坚实的基础。不断实践和学习,你将能够更熟练地运用JDBC进行数据库交互。祝你在学习过程中收获满满,早日成为...

    jdbc 简单实例 教你学会Java连数据库

    6. **数据库操作的其他注意事项**: - 为了性能和资源管理,应使用try-with-resources或手动关闭数据库资源(如`Connection`,`Statement`,`ResultSet`)。 - 事务管理,如`conn.setAutoCommit(false)`来开启手动...

Global site tag (gtag.js) - Google Analytics