事务学习(一)

一、事务原则
当事务处理系统创建事务时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。这些特性称为ACID特性。

1、原子性(Atomicity ):
原子性属性用于标识事务是否完全地完成,一个事务的任何更新要在系统上完全完成,如果由于某种原因出错,事务不能完成它的全部任务,系统将返回到事务开始前的状态。
2、一致性( Consistency):
事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。因为事务开
始时系统处于一致状态,所以现在系统仍然处于一致状态。
3、隔离性或独立性( Isolation):
在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
4、持久性(Durabilily):
持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件本身失败,系统的状态仍能通过在日志中记录事务完成的任务进行重建。持久性的概念允许开发者认为不管系统以后发生了什么变化,完成的事务是系统永久的部分。

二、实现原理
1、JDBC事务
2、JTA(Java Transaction API)事务 / Java 事务服务 (JTS;Java Transaction Service)
分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。JTA 事务有效的屏蔽了底层事务资源,使应用可以以透明的方式参入到事务处理中;但是与本地事务相比,XA 协议的系统开销大,在系统开发过程中应慎重考虑是否确实需要分布式事务。若确实需要分布式事务以协调多个事务资源,则应实现和配置所支持 XA 协议的事务资源,如 JMS、JDBC 数据库连接池等。使用 JTA 处理事务的示例如下(注意:connA 和 connB 是来自不同数据库的连接)
JTA 事务处理:

public void transferAccount() { 
         UserTransaction userTx = null; 
        Connection connA = null; 
        Statement stmtA = null; 

        Connection connB = null; 
        Statement stmtB = null; 

        try{ 
              // 获得 Transaction 管理对象
            userTx = (UserTransaction)getContext().lookup("\
                  java:comp/UserTransaction"); 
            // 从数据库 A 中取得数据库连接
            connA = getDataSourceA().getConnection(); 

            // 从数据库 B 中取得数据库连接
            connB = getDataSourceB().getConnection(); 

                       // 启动事务
            userTx.begin();

            // 将 A 账户中的金额减少 500 
            stmtA = connA.createStatement(); 
            stmtA.execute("
           update t_account set amount = amount - 500 where account_id = 'A'");

            // 将 B 账户中的金额增加 500 
            stmtB = connB.createStatement(); 
            stmtB.execute("\
            update t_account set amount = amount + 500 where account_id = 'B'");

            // 提交事务
            userTx.commit();
            // 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
        } catch(SQLException sqle){ 

            try{ 
                  // 发生异常,回滚在本事务中的操纵
                 userTx.rollback();
                // 事务回滚:转账的两步操作完全撤销 
                //( 数据库 A 和数据库 B 中的数据更新被同时撤销)

                stmt.close(); 
                conn.close(); 
                ... 
            }catch(Exception ignore){ 

            } 
            sqle.printStackTrace(); 

        } catch(Exception ne){ 
            e.printStackTrace(); 
        } 
    }

begin()- 开始一个分布式事务,(在后台 TransactionManager 会创建一个 Transaction 事务对象并把此对象通过 ThreadLocale 关联到当前线程上 )
commit()- 提交事务(在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务提交)
rollback()- 回滚事务(在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务回滚)
getStatus()- 返回关联到当前线程的分布式事务的状态 (Status 对象里边定义了所有的事务状态,感兴趣的读者可以参考 API 文档 )
setRollbackOnly()- 标识关联到当前线程的分布式事务将被回滚
3、容器事务
mysql事务原理
在mysql中用的最多的存储引擎有:innodb,bdb,myisam ,memory 等。其中innodb和bdb支持事务而myisam等不支持事务。默认情况下MySQL开启的是autocommit模式,也就是隐含的将每条语句当做一个事务处理,每条SQL都会被自动提交。
原子性、稳定性和持久性是通过redo 和 undo 日志文件实现的,不管是redo还是undo文件都会有一个缓存我们称之为redo_buf和undo_buf。同样,数据库文件也会有缓存称之data_buf。
Undo日志记录某数据被修改前的值,可以用来在事务失败时进行rollback。
A 事务开始
B 记录AA=3到undo_buf
C 修改AA=1
D 记录BB=5到undo_buf
E 修改BB=7
F 将undo_buf写到undo(磁盘)
G 将data_buf写到datafile(磁盘)
H 事务提交

如果事务在F之前崩溃由于数据还没写入磁盘,所以数据不会被破坏。
如果事务在G之前崩溃或者回滚则可以根据undo恢复到初始状态。
但是单纯使用undo保证原子性和持久性需要在事务提交之前将数据写到磁盘,浪费大量I/O。

Redo日志记录某数据块被修改后的值,可以用来恢复未写入data file的已成功事务更新的数据。
A 事务开始
B 记录AA=3到undo_buf
C 修改AA=1 记录redo_buf
D 记录BB=5到undo_buf
E 修改BB=7 记录redo_buf
F 将redo_buf写到redo(磁盘)
G 事务提交
F之前崩溃由于所有数据都在内存,恢复后重新冲磁盘载入之前的数据,数据没有被破坏。
FG之间的崩溃可以使用redo来恢复。
G之前的回滚都可以使用undo来完成。
三、事务并发处理可能引起的问题
脏读(dirty read) 一个事务读取了另一个事务尚未提交的数据
当A事务update后,B事务select读取到A尚未提交的数据,此时A事务rollback,则B读到的数据是无效的”脏”数据。
不可重复读(non-repeatable read) 一个事务的操作导致另一个事务前后两次读取到不同的数据
当B事务select读取数据后,A事务update操作更改B事务select到的数据,此时B事务再次读去该数据,发现前后两次的数据不一样。
幻读(phantom read) 一个事务的操作导致另一个事务前后两次查询的结果数据量不同。
当B事务select读取数据后,A事务insert或delete了一条满足A事务的select条件的记录,此时B事务再次select,发现查询到前次不存在的记录(“幻影”),或者前次的某个记录不见了。
四、事务隔离级别
JDBC定义了五种事务隔离级别:

  • TRANSACTION_NONE JDBC驱动不支持事务
  • TRANSACTION_READ_UNCOMMITTED允许脏读、不可重复读和幻读。
  • TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。
  • TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,不能处理幻读。
  • TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值