zoukankan      html  css  js  c++  java
  • JDBC conn.setAutoCommit(false) 问题

    **********

    做项目是否都有必要设置conn.setAutoCommit(false)?

    public void updateCoffeeSales(HashMap<String, Integer> salesForWeek)

        throws SQLException {

        PreparedStatement updateSales = null;

        PreparedStatement updateTotal = null;

        String updateString =

            "update " + dbName + ".COFFEES " +

            "set SALES = ? where COF_NAME = ?";

        String updateStatement =

            "update " + dbName + ".COFFEES " +

            "set TOTAL = TOTAL + ? " +

            "where COF_NAME = ?";

        try {

            con.setAutoCommit(false);

            updateSales = con.prepareStatement(updateString);

            updateTotal = con.prepareStatement(updateStatement);

            for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) {

                updateSales.setInt(1, e.getValue().intValue());

                updateSales.setString(2, e.getKey());

                updateSales.executeUpdate();

                updateTotal.setInt(1, e.getValue().intValue());

                updateTotal.setString(2, e.getKey());

                updateTotal.executeUpdate();

                con.commit();

            }

        } catch (SQLException e ) {

            JDBCTutorialUtilities.printSQLException(e);

            if (con != null) {

                try {

                    System.err.print("Transaction is being rolled back");

                    con.rollback();

                } catch(SQLException excep) {

                    JDBCTutorialUtilities.printSQLException(excep);

                }

            }

        } finally {

            if (updateSales != null) {

                updateSales.close();

            }

            if (updateTotal != null) {

                updateTotal.close();

            }

            con.setAutoCommit(true);

        }

    }

    http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html

    画红线的代码是否有必要?

    csdn帖子:

    一般来讲,大家对数据库中的表单,主要是增、删、改、查 这四个操作,如果你的程序当中,遇到一次业务逻辑需要两次或两次以上的对相同数据表的增删改操作,那么,为了数据的一致性,(或者具体说,在你的一次业务逻辑的处理过程中,其他(线程或程序或业务处理)的对相同数据的相同两次查询所得结果相同。)我们会利用数据库的事务操作,将一次业务逻辑所包含的所有操作封装在一个事务里,一次将多个操作进行提交。
    而conn的setAutoCommit方法,是指,在事务当中,是否执行一条语句就自动提交一次。
    这样的话,如果,你想在一个事务里进行多个操作。就必然将setAutoCommit的参数设置成false,在多个操作的最后调用conn.commit()方法,进行手动提交。

    有时候是很必要的,特别是纯JDBC的事务控制,就更需要了,举个例子来说吧,你要删除某个部门,而该部门下又有多个员工,这时候,你就得先删除该部门下的所有员工,这里,你就得把两个操作(删除员工和删除部门)放在同一个业务中了,而这种情况下是很危险的,你可能成功删除了该部门下的所有员工而删除该部门的时候又遇到了异常即没有成功删除。这时候,如果你原先没有把事务提交方式改为手工提交,而之前删除的员工的事务又已经自动提交了,就无法进行数据回滚,员工的数据就找不回了,这时,你会45度仰望天空,感叹一声:“啊,悲剧终于发生了”。

    误用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等,都一定要记住在处理完之后要提交或者回滚哦。

  • 相关阅读:
    qt.qpa.plugin Could not load the Qt platform plugin xcb
    深度学习模型在移动端的部署
    ccproxy
    Java版本
    第四篇 -- Go语言string转其他类型
    第三篇 -- Go语言其他类型转String方法
    第二篇 -- Go语言转义字符与变量声明
    第五十三篇 -- MFC美化界面2
    C++第五十二篇 -- 多线程之消息传递
    第一篇 -- Go环境的搭建以及Hello World程序编写
  • 原文地址:https://www.cnblogs.com/youxin/p/2782426.html
Copyright © 2011-2022 走看看