1、事务
事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取。事务的正确执行使得数据库从一种状态转换成另一种状态。
当操作序列中的所有操作都成功执行时,事务的状态未成功。当任一操作失败时,事务的状态为失败,此时必须将程序状态返回至事务未执行时的状态,即回滚。
1.2 四个特性
原子性(Atomicity):事务中的所有操作是不可再分割的原子单位,事务中的所有操作是一个整体,或者整体执行成功,亦或者整体执行失败。
一致性(Consistency):事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论执行成功与否,参与转账的两个帐号余额值和应该是不变的。
隔离性(Isolation):在并发操作中,不同事务之间应该隔离开来,每个并发中的事务的执行不会相互干扰。
持久性(Durability):一旦事务提交成功,事务中的所有数据更新必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重新启动时,也必须能保证通过某种机制恢复数据。
1.3 数据库的两种事务模式
(1)自动提交模式:每个SQL语句都是一个独立的事务,当数据库系统执行完一个SQL语句后,会自动提交事务。
(2)手动提交模式:必须由数据库客户程序显示指定事务开始边界和结束边界。
默认是自动提交模式
1.4 数据库读写中的并发事务问题
(1)脏读(Dirty Read):在事务的执行过程中,读取到了其他事务的 未提交 的数据,即读到了脏数据。
(2)不可重复读(Unrepeatable Read):在事务的执行过程中,读到了其他事务 修改后 的数据,换句话说在该事务中的不同时间点读取到了不一致的数据,即不可重复读。
(3)幻读/虚读(Phantom Read):在事务的执行过程中,读取到了其他事务对 记录数 修改后的数据,对同一张表的两次查询的 COUNT(*) 不一致。
不可重复读与幻读的区别:
不可重复读:强调的是数据 内容 的不一致,主要针对 UPDATE 的修改。
幻读:强调的是 记录数 的不一致,主要针对 INSERT/DELETE 的修改。
1.5 四个隔离级别
并发事务问题的产生原因是,未能遵守事务的隔离特性
(1)串行化(SERIALIZABLE):所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
(2)可重复读(REPEATABLE_READ):该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
(3)读已提交(READ_COMMITTED):该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
(4)读未提交(READ_UNCOMMITTED):该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
不同隔离级别可避免的并发问题
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
串行化 | Y | Y | Y |
可重复读 | Y | Y | |
读已提交 | Y | ||
读未提交 |
2、应用
当一个事务未完成之前,写操作不会真正写入数据库。同时需要注意,一个事务是以提交(commit)或者回滚(rollback)结束,否则会发生死锁,导致表被锁死,之后的任何正确操作都不会成功。
2.1 MySQL事务的应用
查看隔离级别语句:SELECT @@TX_ISOLATION;
启用事务:START TRANSACTION;
设置隔离级别:set [global/session] transaction isolation level;
提交:COMMIT;
回滚:ROLLBACK;
# 开启事务
START TRANSACTION;
# 执行事务 SQL 语句
# SQL1
UPDATE Test_Table
SET name = hhh
WHERE id = 1;
# SQL2
UPDATE Test_Table
SET name = xxx
WHERE id = 2;
# 提交事务
COMMIT;
2.2 JDBC事务的应用
//设置隔离级别
conn.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
//启用事务
conn.setAutoCommit(false);
//提交
conn.commit();
//回滚
conn.rollback();
try
{
conn = jdbcTest.getConnection(sHostName, sPortNumber, sSid, userName, password);
conn.setTransactionIsolation(TRANSACTION_REPEATABLE_READ);
conn.setAutoCommit(false);
String SQL = "insert into Test_Table values('name1','age1')";
jdbcTest.excute(conn, SQL);
SQL = "insert into Test_Table values('name2','age2')";
jdbcTest.excute(conn, SQL);
conn.commit();
} catch (SQLException e)
{
if (conn != null)
{
try
{
conn.rollback();
} catch (SQLException e1)
{
e1.printStackTrace();
}
}
e.printStackTrace();
} finally
{
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
原文作者:萌太隆
原文地址:https://blog.csdn.net/swl979623074/article/details/79416470