欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

事务—事务模型

最编程 2024-04-23 13:45:36
...

程序猿基础知识的学习、理解、整理——事务(方方土)

事务,看似很简单,其实很复杂,作为一个程序猿,你对事务到底了解多少。下面主要以一个JAVA程序猿的角度来阐述一下事务。以下内容主要是读书《java事务设计策略》的笔记以及基于平时一些认知的总结,非原创!!^_^,还有“简书”真实不错,很好的一个工具,推荐使用

什么是事务?ACID(原子性、一致性、独立性、持久化)

  • 原子性:事务内的操作作为一个独立的单元提交,或者回滚;
  • 一致性:保证事务的操作部破坏数据的完整性约束;
  • 独立性:保证事务间的可见性
  • 持久化:保证事务的操作是可持久的;
  • 什么是事务模型?这里提到的事务模型主要是阐述的是怎么样来管理事务的概念。分为以下三种事务模式:本地事务模型,编程式事务模型,声明式事务模型

    为什么要提事务模型这个概念,其实本质上事务模型也就是一个抽象的概念,主要体现的是开发人员在不同的场景下,用不同的方法来实现事务的管理,从以下内容的描述,希望可以叫直观地表达了这些事务模型的不同点,这些事务模型的优缺点点。

    从我的编程习惯来说,经历过本地事务模型的阶段,经历过编程式事务模型的阶段,到现在基本上使用声明式的事务模型,我感觉这三种方式是不断进化的过程。用过才知道,哪个好。就好比大家现在都用spring,都说spring好,那它究竟好在哪里呢?究竟解决了些什么问题呢?只有比较才知道。

  • 本地事务模型:事务由本地资源管理器来管理,对于开发人员而言,管理的是“连接”,而非“事务”
    • 直观感受一下什么叫“本地事务模型”

    public void update TradeOrder(TradeOrderDate order)

    throws Exception{

    DataSource ds = (DataSource)

    (new InitialContext()).lookup("jdbc/MasterDS");

    conn = ds.getConnection();

    conn.setAutoCommit(false);

    Statement stmt  = conn.createStatement();

    String sql = "update trade_order ....";

    try{

    stmt.excuteUpdate(sql);

    conn.commit();

    }catch(Exception e){

    conn.rollback();

    throws e;

    }finally{

    stmt.close;

    conn.close;

    }

    }

    很简单的一个jdbc操作的一个函数,就在这个函数中包含了本地事务模型的概念,标粗部分,其实在这个函数中,对于开发人员而言,获取的是一个数据库的连接conn,而不是一个事务,所以在这个函数中,对于开发人员而言,没有事务的操作,事务是通过conn委托给数据库去操作的;

    • “本地事务模型”存在什么问题

    1、对于开发人员的侵入性较大,开发人员在编码的时候,时刻要想着commit,commit,commit,且都是一些重复代码;

    2、如果涉及两个方法调用,比如有方法A,调用方法B和方法C,大家想想,如果采用本地事务模型,那么这个时候的方法A还是一个事务吗?所以,开发人员在设计的时候,要想的很清楚,到底有哪些方法

    3、如果涉及到XA,比如一个方法中既有jdbc操作,又有jms操作,该怎么办呢?

    4、所以,如果是自己写一个jdbc的小DEMO,那么可以用本地事务模型这种方式来玩玩,如果是在大型的系统建设中,就务必要杜绝。

  • 编程式事务模型:事务通过JTA以及底层的JTS实现来管理,对于开发人员而言,管理的是“事务”,而非“连接”
    • 直观感受一下什么叫“编程式事务模型”

    Public void updateTradeOrder(TradeOrderData order)
    throws Exception{
    UserTransaction txn = sessionCtx.getUserTransaction();
    txn.begin();
    try{
    TradeOrderDao dao = new TraderOrderDao();
    dao.updateTradeOrder(order);
    txn.commit();
    }catch(Excption e){
    log.fatal(e);
    txn.rollback();
    throw e;
    }
    }
    很简单的一个更新操作的一个函数,就在这个函数中包含了编程式事务模型的概念,标粗部分,其实在这个函数中,对于开发人员而言,获取的是一个事务对象txn,而不是一个数据库连接,所以在这个函数中,对于开发人员而言,是通过txn来管理事务的;

    • “编程式事务模型”存在什么问题

    1、编程式事务,事务的管理要由开发人员自己来管理,要考虑好事务提交,事务在异常情况下的处理等等事宜,是一件比较繁琐,容易出错的事情
    2、编程式事务的上下文传递问题,什么是事务上下文传递呢?举例来说,方法A调用了方法B,(方法A和方法B都采用编程式的事务模型),那么方法A中创建的事务无法传递到方法B中。大家想想看,其实很多业务场景,在方法A调用方法B的这种场景下,我们都认为方法A整体是一个事务,但是如果采用编程式事务模型,那么它内部本质是两个事务;

  • 声明式事务模型:事务由容器进行管理,对于开发人员而言,几乎不管理事务
    • 直观感受一下什么叫“声明式事务模型”

    @TransactionAttribute(TransactionAttribute.Type.Required)
    public void updateTradeOrder(TradeOrderData order)
    throw Exception{
    try{
    TradeOrderDao dao = new TradeOrderDao();
    dao.updateTradeOrder(order);
    }catch (Exception e){
    sessionContext.setRollbackOnly();
    throw e;
    }
    }
    很简单的一个操作,大家发现在这个函数中,没有用到连接,也没有看到事务,而只是有一行注解,就是通过这行注解就将这个函数的失去托管给容器去管理了。

    • “声明式事务模型中的事务属性”

    1、Required(需要一个事务,如果上下文中已有事务,则用之,如没有,则新建一个事务。说明上下文事务是传递的)
    2、Mandatory(需要一个事务,如果上下文中没有事务,就报异常。说明上下文事务是传递的,而且必须要通过上下文事务的传递)
    3、RequiredNew(需要一个事务,如果上下文中有事务,将该事务挂起,新开一个事务。说明上下文事务是不传递的)
    4、Supports(不需要一个事务,如果上下文中有事务,则用之,如果没有,则不用事务)
    5、NotSupported(不需要一个事务,如果上下文中有事务,则暂停事务,运行结束后,再开启事务)
    6、Never(不需要一个事务,如果在上下文中有事务,就报异常)

    好,到这里,有两个问题,需要大家去思考一下?
    1、到底我们的哪些方法需要事务?哪些方法不需要事务?事务给我们带来的开销是什么?
    2、在我们的程序中,事务到底要控制在哪里,控制在在DAO层,还是控制在Service层?为什么?