您的位置:首页 > 其它

JDBC conn.setAutoCommit(false) 问题

2012-11-22 12:28 351 查看
**********

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

publicvoidupdateCoffeeSales(HashMap<String,Integer>salesForWeek)

throwsSQLException{

PreparedStatementupdateSales=null;

PreparedStatementupdateTotal=null;

StringupdateString=

"update"+dbName+".COFFEES"+

"setSALES=?whereCOF_NAME=?";

StringupdateStatement=

"update"+dbName+".COFFEES"+

"setTOTAL=TOTAL+?"+

"whereCOF_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(SQLExceptione){

JDBCTutorialUtilities.printSQLException(e);

if(con!=null){

try{

System.err.print("Transactionisbeingrolledback");

con.rollback();

}catch(SQLExceptionexcep){

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
Connectioncon=null;

2try{

3
con=getConnection();

4
con.setAutoCommit(false);

/*

5
*updateUSERsetname=’winson’whereid=’000001’;

*/

6
con.commit();

7
}finally{

8
if(con!=null){

9
try{

10
con.close();

11
}catch(SQLExceptione){

12
e.printStackTrace();

13
}

}

}

分析:问题就出现在第4行,写代码的人把数据库连接con设置成非自动提交,但没有在执行出现异常的时候进行回滚。如果在执行第5行的时候出现异常,con既没有提交也没有回滚,表USER就会被锁住(如果oracle数据库就是行锁),而这个锁却没有机会释放。有人会质疑,在执行con.close()的时候不会释放锁吗?因为如果应用服务器使用了数据库连接池,连接不会被断开。

附:在oracle上查看锁的方法:select*fromv$lock_object或者select*fromv$lock.

JDBC的api文档是这样对setAutoCommit方法解释的:

Setstheconnection's
auto-commitmodetoenableAutoCommit.

NewlycreatedConnectionobjectsare
inauto-commitmodebydefault,whichmeansthatindividualSQLstatementsare
committedautomaticallywhenthestatementiscompleted.Tobeabletogroup
SQLstatementsintotransactionsandcommitthemorrollthembackasaunit,
auto-commitmustbedisabledbycallingthe
methodsetAutoCommitwithfalseasitsargument.Whenauto-commitis
disabled,theusermustcalleither
thecommitorrollbackmethodexplicitlytoenda
transaction.
(一定不能大意哦,如果设置成非自动提交,在最后一定要调用commit或者rollback方法)

[b]
Thecommitoccurswhenthestatementcompletesorthenextexecuteoccurs,
whichevercomesfirst.InthecaseofstatementsreturningaResultSetobject,
thestatementcompleteswhenthelastrowoftheresultsethasbeenretrieved
ortheResultSetobjecthasbeenclosed.Inadvancedcases,asingle
statementmayreturnmultipleresultsaswellasoutputparametervalues.In
thiscase,thecommitmayoccurwhenallresultsandoutputparametervalues
havebeenretrieved,orthecommitmayoccuraftereachresultisretrieved.
[/b]

参考正确的写法应该是:

Connectioncon=null;


try{


con=getConnection();


con.setAutoCommit(false);


/*


*dowhatyouwanthere.


*/


con.commit();


}catch(Throwablee){


if(con!=null){


try{


con.rollback();


}catch(SQLExceptione1){


e1.printStackTrace();


}


}


thrownewRuntimeException(e);


}finally{


if(con!=null){


try{


con.close();


}catch(SQLExceptione){


e.printStackTrace();


}


}


}




这种疏忽很容易出现,但又导致非常严重的运行问题。所以在这里作个提醒,以后在处理外部资源的时候一定要格外小心。今天还发现代码中一些地方滥用synchronized关键字,导致系统性能受到很大的影响,处理不当跟前面提到问题一起出现,那系统就是时候over了。

另外,如果不是自己来处理事务,可能在用hibernate或者ejb等,都一定要记住在处理完之后要提交或者回滚哦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: