程序猿基础知识的学习、理解、整理——事务(方方土)
事务,看似很简单,其实很复杂,作为一个程序猿,你对事务到底了解多少。下面主要以一个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,那么可以用本地事务模型这种方式来玩玩,如果是在大型的系统建设中,就务必要杜绝。
- 直观感受一下什么叫“编程式事务模型”
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层?为什么?