Connection.setAutoCommit使用的注意事项

原文地址:http://blog.csdn.net/xiayimiaokuaile/article/details/6422032


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

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

setAutoCommit(false)的误用
设定setAutoCommit(false)没有在catch中进行Connection的rollBack操作,操作的表就会被锁住,造成数据库死锁):
误用Connection.setAutoCommit导致的数据库死锁问题。

系统在发布到用户的的服务器了,运行一段时间偶尔出现某些功能不能正常运行,甚至不能自动恢复,严重导致服务器当机,表现为服务器不响应用户的请求,数据库有大量的锁。在服务器重启后才能恢复正常。今天通遍的查看了一下代码,初步分析了原因,记录了下来,跟大家交流交流。
先看下面一段有问题的代码:
 
       Connection con = null;
     try{
         con = getConnection();
         con.setAutoCommit(false);
           /*
         * update USER set name=’winson’ where id=’000001’;
            */
         con.commit();
      }finally{
          if(con!=null){
              try {
                con.close();
             } catch (SQLException e) {
                e.printStackTrace();
             }
           }
       }

分析:问题就出现在第 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等,都一定要记住在处理完之后要提交或者回滚哦。



>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>长长的分割线>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
原文地址:http://blog.sina.com.cn/s/blog_81547cad01014rnk.html

事务操作数据:

(一)

eg:

假如银行转账系统

从张三的账户转1000元到小罗的账户
这个操作需要分两步
1.张三账户减少1000元
2.小罗账户增加1000元
假如于到断电等等,而刚好张三减了1000,而此时小罗却不增加。。。。可以想象银行这下有事做了

所以使用事务操作数据来搞定

 

(2)

java使用事务非常简单,首先调用conn.setAutoCommit(boolean b)方法,传入一个false,这样将不会自动提交,而需要使用conn.commit()方法,手动提交事务,当然只有在确认两个步骤都没有出错的情况下,才能提交,这样才能保证整个操作的完整性,一旦出错,使用conn.rollback()方法,回滚事务,这样的话,整个事务都将不被提交。那么如何判断有没有出错呢,非常简单,执行数据库操作的方法,都会抛出java.sql.SQLException,所以需要使用try……catch语句块捕获异常在catch块中,使用conn.rollback()回滚事务即可
       在数据库调用的javabean中conn.setAutoCommit()的功能是每执行一条SQL语句,就作为一次事务提交。但一般在项目中很有可能需要执行多条SQL语句作为一个事务。若有一个执行不成功,就会rollback();

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

(3)参数:true和false

假设如下:
1 数据库一个表格有50条记录
2 你设置参数为false
则在你执行整个查询SQL期间,一直是没有事务的,那么如果你的查询用到了一些函数,这些函数包含了多个查询语句,那么有可能会出现不一致的情况。
也就是说,函数、存储过程等,他们都将运行在非事务的环境下。
而你设置为true,则没有任何问题了,读一致性将保证不会出现问题。



你可能感兴趣的:(sql,数据库,事务)