事务

事务

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

  • 为什么要有事务?

为了确保逻辑的成功。 例子: 银行的转账。

使用命令行方式演示事务。

  • 开启事务

    start transaction;

  • 提交或者回滚事务

    commit; 提交事务, 数据将会写到磁盘上的数据库
    rollback ; 数据回滚,回到最初的状态。

  1. 关闭自动提交功能。
    事务

  2. 演示事务
    事务

使用代码方式演示事务

代码里面的事务,主要是针对连接来的。

  1. 通过conn.setAutoCommit(false )来关闭自动提交的设置。

  2. 提交事务 conn.commit();

  3. 回滚事务 conn.rollback();

     @Test
     public void testTransaction(){
     	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();
     		
     		int a = 10 /0 ;
     		//加钱, 给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);
     	}
     }
    

事务的特性

  • 原子性

    指的是 事务中包含的逻辑,不可分割。

  • 一致性

    指的是 事务执行前后。数据完整性

  • 隔离性

    指的是 事务在执行期间不应该受到其他事务的影响

  • 持久性

    指的是 事务执行成功,那么数据应该持久保存到磁盘上。

事务的安全隐患

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


  • 脏读 不可重读读 幻读.

    • 脏读

    一个事务读到另外一个事务还未提交的数据

    • 不可重复读

    一个事务读到了另外一个事务提交的数据 ,造成了前后两次查询结果不一致。

读未提交 演示

  1. 设置A窗口的隔离级别为 读未提交
    事务
  2. 两个窗口都分别开启事务
    事务
  • 丢失更新

读已提交演示

  1. 设置A窗口的隔离级别为 读已提交
    事务

  2. A B 两个窗口都开启事务, 在B窗口执行更新操作。
    事务

  3. 在A窗口执行的查询结果不一致。一次是在B窗口提交事务之前,一次是在B窗口提交事务之后。
    事务

这个隔离级别能够屏蔽脏读的现象,但是引发了另一个问题,不可重复读。

可串行化

如果有一个连接的隔离级别设置为了串行化,那么谁先打开了事务,谁就有了先执行的权利,谁后打开事务,谁就只能得着,等前面的那个事务,提交或者回滚后,才能执行。但是这种隔离级别一般比较少用。容易造成性能上的问题。效率比较低。

  • 按效率划分,从高到低

    读未提交 > 读已提交 > 可重复读 > 可串行化

  • 按拦截程度 ,从高到底

    可串行化 > 可重复读 > 读已提交 > 读未提交

事务总结

  1. 在代码里面会使用事务

     conn.setAutoCommit(false);
    
     conn.commit();
    
     conn.rollback();
    
  2. 事务只是针对连接连接对象,如果再开一个连接对象,那么那是默认的提交。

  3. 事务是会自动提交的。

安全隐患

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

写

	丢失更新。

隔离级别

读未提交

引发问题: 脏读

读已提交

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

可重复读

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

可串行化

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

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

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

丢失更新
事务

解决丢失更新

  • 悲观锁

    可以在查询的时候,加入 for update
    事务

  • 乐观锁

    要求程序员自己控制。
    事务