setAutoCommmit保持数据的完整性
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();
}
}
}
}
setAutoCommmit保持数据的完整性的更多相关文章
- oracle维护数据的完整性
介绍: 数据的完整性用于确保数据库数据遵从一定的商业的逻辑规则.在oracle中,数据完整性可以使用约束.触发器.应用程序(过程.函数)三种方法来实现,在这三种方法中,因为约束易于维护,并且具有最好的 ...
- MySQL——保证数据的完整性
为了防止垃圾的产生,从而影响数据库的执行效率. 1实体完整性——行数据的有效性 唯一约束(unique).主键约束(primary key) 2域完整性——列数据的有效性 非空约束(not nul ...
- 代码中添加事务控制 VS(数据库存储过程+事务) 保证数据的完整性与一致性
做人事档案的系统考虑到数据的安全性与一致性,毕竟是要对外上线.真正投入使用的项目,数据库的可靠性与安全性上我们开发人员要考虑的就很多了,记得做机房收费系统时注册新卡是自己为了简单,写成了一个存储过程( ...
- Oracle 维护数据的完整性 一 索引
简介:索引是用于加速数据存取的数据对象,合理的使用索引可以大大降低i/o 次数,从而提高数据的访问性能. 当我们从一张表中检索我们需要的数据是,oralce往往会进行全表扫描,就是遍历所有的数据行,来 ...
- Kafka在高并发的情况下,如何避免消息丢失和消息重复?kafka消费怎么保证数据消费一次?数据的一致性和统一性?数据的完整性?
1.kafka在高并发的情况下,如何避免消息丢失和消息重复? 消息丢失解决方案: 首先对kafka进行限速, 其次启用重试机制,重试间隔时间设置长一些,最后Kafka设置acks=all,即需要相应的 ...
- Oracle 维护数据的完整性 一 约束
简介:约束用于确保数据库满足特定的商业规则.在Oracle中,约束包括以下几种: 1.not null 非空约束 该劣质不能为null 2.unique 唯一约束 ...
- 从零自学Hadoop(16):Hive数据导入导出,集群数据迁移上
阅读目录 序 导入文件到Hive 将其他表的查询结果导入表 动态分区插入 将SQL语句的值插入到表中 模拟数据文件下载 系列索引 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并 ...
- 大数据系列(2)——Hadoop集群坏境CentOS安装
前言 前面我们主要分析了搭建Hadoop集群所需要准备的内容和一些提前规划好的项,本篇我们主要来分析如何安装CentOS操作系统,以及一些基础的设置,闲言少叙,我们进入本篇的正题. 技术准备 VMwa ...
- MVVM中数据验证之 ViewModel vs. Model
MMVM模式示意图. View绑定到ViewModel,然后执行一些命令在向它请求一个动作.而反过来 ...
随机推荐
- 前端---DOM
一.介绍: http://www.cnblogs.com/wupeiqi/articles/5643298.html 什么是DOM? DOM字面意思是文档对象模型,DOM将网页内的元素与内容呈现为一个 ...
- SpringMVC学习笔记(三)
一.SpringMVC使用注解完成 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 <!--configure the setti ...
- AIX 环境下ODM库同步
IBM AIX v5.3操作系统环境下有时会出现ODM库与rootvg硬盘上数据不同步的情况.使用命令lsvg -l datavg检查文件系统类型,发现显示为"???"这就表示OD ...
- Winform 五种常用对话框控件的简单使用
OpenFileDialog(打开文件对话框)FolderBrowserDialog(浏览文件夹对话框)SaveFileDialog(保存文件对话框)ColorDialog(颜色选择对话框)FontD ...
- Winform 窗体控件随窗体自动(等比例)调整大小
新建窗体程序了,添加窗体事件Load(加载窗体时).Resize(调整控件大小时).自定义方法setTag(获取控件的width.height.left.top.字体大小等信息的值).setContr ...
- 实例学习SQL的Select命令
1.查找员工的编号.姓名.部门和出生日期,如果出生日期为空值,--显示日期不详,并按部门排序输出,日期格式为yyyy-mm-dd.select emp_no ,emp_name ,dept ,isnu ...
- JavaScript 中this与Dom中的注意
对于下面这段代码: <script type='text/javascript'> function testThis() { console.log(this); } </scri ...
- unity3d 射弹基础案例代码分析
#pragma strict import UnityEngine.UI; function Start () { } var speed : int = 5; var newobject : Tra ...
- new和alloc的区别
简单来说,new和alloc在功能上基本没有什么区别,都是分配内存,初始化对象. 但是,调用new的话,只能通过默认的init方法来初始化对象,而alloc可以通过其他的初始化方法如:-(instan ...
- 第11章 .NET Remoting
11.1理解remoting 11.1.1应用程序域基本概念 .NET提供了一项技术,使得跨应用程序域中的对象也可以相互访问,该技术就是.NET remoting.(185) 11.1.2应用程序域的 ...