一、事务(Transaction):其实是一组操作(包含许多个单一的逻辑)。只要有一个逻辑没有执行成功,那么都算失败。 所有的数据都回归到最初的状态(回滚)

例如:银行转账

A用户向B用户转账,这样的话转账中就有两个逻辑操作,1、A用户账户金额要减少  2、B用户账户金额要增加,此时就需要把这两个逻辑操作放入事务中

代码格式:

@Testpublic voidtestTransaction(){
Connection conn= null;
PreparedStatement ps= null;
ResultSet rs= null;try{
conn=JDBCUtil.getConn();//连接,事务默认就是自动提交的。 关闭自动提交。
conn.setAutoCommit(false);
String sql= "update account set money = money - ? where id = ?";
ps=conn.prepareStatement(sql);//扣钱, 扣ID为1 的100块钱
ps.setInt(1, 100);
ps.setInt(2, 1);
ps.executeUpdate();//加钱, 给ID为2 加100块钱
ps.setInt(1, -100);
ps.setInt(2, 2);
ps.executeUpdate();//成功: 提交事务。
conn.commit();
}catch(SQLException e) {try{//事变: 回滚事务
conn.rollback();
}catch(SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps, rs);
}
}

二、事务的特性

①、原子性:事务中包含的逻辑,不可分割。

②、一致性:事务执行前后。数据完整性

③、隔离性:事务在执行期间不应该受到其他事务的影响

④、持久性:事务执行成功,那么数据应该持久保存到磁盘上。

三、隔离级别

①、读未提交(read uncommitted)

引发问题: 脏读

②、读已提交(read committed)

解决: 脏读 , 引发: 不可重复读,SQL Server没有这个问题

③、可重复读(repeatable-read)

解决: 脏读 、 不可重复读 , 引发: 幻读

④、可串行化(SERIALIZABLE)

解决: 脏读、 不可重复读 、 幻读

mySql 默认的隔离级别是 可重复读

Oracle 默认的隔离级别是  读已提交

Sql Server 默认的隔离级别是  读已提交

四、事务的安全隐患

不考虑隔离级别设置,那么会出现以下问题

①、读

脏读:一个事务读到了另一个事务未提交的数据

事务A:

USEBankGO

--使用默认隔离级别

BEGIN TRANSACTION
UPDATE ACCOUNT SET Money=Money-300 WHERE Id=1
WAITFOR DELAY '00:00:10'
ROLLBACK TRANSACTION

事务B:

USEBankGO
--设置隔离级别:未提交读
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION
--发生在事务回滚前
SELECT * FROM ACCOUNT WHERE Id=1
WAITFOR DELAY '00:00:10'
--发生在事务回滚后
SELECT * FROM ACCOUNT WHERE Id=1
COMMIT TRANSACTION

先执行事务A再执行事务B结果:

java 手动事务不生效 java手动控制事务_java 手动事务不生效

不可重复读:一个事务读到了另一个事务已提交的数据,造成前后两次查询结果不一致

事务A:

USEBankGO
--使用默认隔离级别
BEGIN TRANSACTION
UPDATE ACCOUNT SET Money=Money-300 WHERE Id=1
WAITFOR DELAY '00:00:10'
COMMIT TRANSACTION --注意
事务B:
USEBankGO
--设置隔离级别:读已提交
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRANSACTION
--发生在事务回滚前
SELECT * FROM ACCOUNT WHERE Id=1
WAITFOR DELAY '00:00:10'
--发生在事务回滚后
SELECT * FROM ACCOUNT WHERE Id=1
COMMIT TRANSACTION

先执行事务B再执行事务A结果:

java 手动事务不生效 java手动控制事务_不可重复读_02

幻读:一个事务读到了另一个事务insert的数据 ,造成前后查询结果不一致

事务A

USE Bank
GO
--使用默认隔离级别
BEGIN TRANSACTION
INSERT INTO ACCOUNT VALUES('Kimi',1000)
COMMIT TRANSACTION
事务B
USEBankGO
--设置隔离级别:读已提交
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
--发生在事务提交前
SELECT * FROMACCOUNTWAITFOR DELAY '00:00:10'
--发生在事务提交后
SELECT * FROMACCOUNTCOMMIT TRANSACTION

先执行事务B再执行事务A结果不一致,为幻读:

java 手动事务不生效 java手动控制事务_不可重复读_03

②、写

丢失更新

java 手动事务不生效 java手动控制事务_java 手动事务不生效_04

java 手动事务不生效 java手动控制事务_不可重复读_05

数据丢失更新可以通过锁机制,来加以控制

五、总结

脏读

更新丢失

不可重复读

幻读

Read Uncommitted

可能

可能

可能

可能

Read Committed

不可能

可能

可能

可能

Repeatable Read

不可能

不可能

不可能

可能

Serializable

不可能

不可能

不可能

不可能