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,然后执行一些命令在向它请求一个动作.而反过来 ...
随机推荐
- disconf系列【2】——解决zk部署情况为空的问题
如下图所示,在安装完成之后,发现zk(zookeeper)部署情况为空. 注:承接上篇,环境未发生改变. 1.解决zk没有启动的问题 查看disconf日志,发现zk没有启动. 实际情况是:zk已经启 ...
- 选项卡切换:自动定时&主动触发事件
最初学习的是手动触发事件,添加的是onmouseover,其中index是关键,tab标签与现实内容的div索引一一对应,遍历tab标签,当鼠标移动到某标签时,触发对应的内容div显示.for(var ...
- linux 学习10 shell 基础
10.1 Shell概述 .Shell是什么 Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动.挂起.停止甚至是编写一 ...
- SQL select 语法(转)
SQL 里面最常用的命令是 SELECT 语句,用于检索数据.语法是: SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expr ...
- hdu 3622 Bomb Game(二分+2-SAT)
Bomb Game Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- ORACLE连接SQLSERVER
一.实验(实验成功) 1.实验目标:ORACLE连接SQLSERVER以及查询数据 2.搭建的环境: oracle 9i 9.0.2.0.1 地址:192.168.40.139 sql2000 的数据 ...
- angular中ng-model,返回数据,拆分数据,展示,名称相同,重新赋值会有冲突
本问题出在angular,1.X版本,我用的是1.5的版本: 问题原因: <input type="number" ng-mode="a" /> & ...
- shell 统计某个文件的行数命令
语法:wc [选项] 文件- 说明:该命令统计给定文件中的字节数.字数.行数.如果没有给出文件名,则从标准输入读取.wc同时也给出所有指定文件的总统计数.字是由空格字符区分开的最大字符串. 该命令各选 ...
- Texture Filter中的Bilinear、Trilinear以及Anistropic Filtering
1. 为什么在纹理采样时需要texture filter(纹理过滤)?我们的纹理是要贴到三维图形表面的,而三维图形上的pixel中心和纹理上的texel中心并不一至(pixel不一定对应texture ...
- X-Frame-Options 响应头
[X-Frame-Options 响应头] 参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options