事务的定义:一组要么同时成功要么同时失败
1.数据事物讲解
1.1事务开始于
-
-
前一个事务结束后,又输入了另一条DML语句
1.2事务结束
-
-
执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
-
执行一条DDL语句,例如grant语句,在这种情况下,会自动执行commit。
-
断开与数据库的连接
-
执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句
2.事务的四大特点
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
-
consistency(一致性)
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
-
isolation(隔离性)
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会 查看中间状态的数据。
事务之间相互隔离
-
durability(持久性)
持久性事务完成之后,它对于系统的影响是永久性的。
3.事务的隔离的级别
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
不可重复读:同一个事务下,两条查询语句结果不一致(读取到了另一个事务修改后的数据)
Repeatable Read可重读
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。
幻读:同一个事务下,两条查询语句结果条数不一致(读取到了另一个事务新增后的数据)
Serializable 可串行化 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。
例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatableread):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的
================mysql中===============
默认隔离级别是:Repeatable Read可重读
查看当前的事务隔离级别:select @@tx_isolation;
更改当前的事务的隔离级别:set transaction isolation level 四个级别之一。
设置隔离级别必须在事务之前
read uncommitted:不能避免脏读,不可重复读,幻读(虚读)
read committed :避免脏读,不可避免不可重复,幻读
repeatable read:避免脏读,不可重复读,不能避免幻读
Serializable:都能避免
4.Java中事务应用
如果jdbc连接处于自动提交模式,默认情况下,则每个sql语句在完成后都会提交到数据库
事务使你能够控制是否何时更改应用于数据库。它将单个SQL语句或一组SQL语句视为一个简单的单元,
如有任何语句失败,则整个事务将失败。
要启动手动事务支持,而不是JDBC驱动程序默认使用的自动提交模式,请使用connection对象的
setAutoCommit()方法。如果将boolean false 传递给setAutoCommit(),则关闭提交,
我们可以传递一个布尔值true来重新打开它。
4.1事务的提交和回滚
完成更改后,我们要提交更改,然后在连接对象上调用commit()方法,如:conn.commit();
否则,要使用连接名为coon的数据库回滚更新,请使用以下代码:conn.rollback();
4.2使用Savepoints
新的jdbc 3.0 Savepoint接口为你提供了额外的事务控制。
设置保存点时,可以在事务中定义逻辑回滚点。如果通过保存点发生错误,则可以使用回滚的方式来撤销
所有更改或仅保存在保存点之后所做的更改。
connection对象有两种新的方法来帮助你管理保存点
setSavepoint(String savepointName):定义新的保存点。它还返回一个是savepoint对象。
releaseSavepoint(Savepoint savepointName):删除保存点。请注意,它需要一个savepoint
对象作为参数。此对象通常是由setSavepoint ()方法生成保存点。
2、执行各个SQL语句,加入到批处理之中
3、如果所有语句执行成功,则提交事务 commit();如果出现了错误,则回滚:rollback()
*************************** * 转账业务来理解事务* *******************************
数据库
MySQL中开两个线程来查看银行账户是否进行转账()注意:每次在执行的时候都要刷新一下
(线程一)
(线程二)
Java中事务表达方式的理解
public class TestTransaction {
@Test
public void testTransaction() {
Connection connection = DBUtils.getConnection();
PreparedStatement ps = null;
//控制事务
try {
connection.setAutoCommit(false);//不自动提交事务 等价于数据库中执行:begin;start transaction;
String sql = "update account1 set money = money -100 where name=?";
ps = connection.prepareStatement(sql);
ps.setString(1, "k");
//执行操作
ps.executeUpdate();
//ps.addBatch();
//模拟断电
int i = 10/0;
String sql1 = "update account1 set money = money +100 where name=?";
ps = connection.prepareStatement(sql1);
ps.setString(1, "h");
ps.executeUpdate();
//提交事务
connection.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception e) {
//回滚 到事务之前的状态
try {
connection.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
//提交事务
try {
connection.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}