单体架构中事务的使用姿式略谈

       不管是单体架构仍是分布式架构,事务必定会使用到的。单体架构下,一般使用数据库自带的ACID机制加上Spring的AOP能够解决大多数场景的需求。分布式事务会比较复杂,有2PC,3PC,TCC等。本文暂不涉及分布式事务,考虑之后另写文章,讨论分布式事务。web

       事务自己是用来保证一次请求或者操做的一致性,完整性的。所以不得不讨论一下一次请求或者一次操做。一次请求能够理解为后台一个controller方法的调用,单体架构下MVC模式使用较多。一般会分为三层,controller用于接收终端的请求,并将数据向serivce层进行传递,须要进行存储的调用下层的dao(mapper)层或者cache层。spring

        那么事务究竟放在哪一层比较合适呢?是controller仍是service?或者dao?数据库

从我的的工做经从来看,把事务放在dao层的作法不是说没有,只是比较少。一般状况下,一个dao的方法用于完成一个数据库操做,删除,修改或者新增。数据库默认一条DDL就是一次事务,经过数据库ACID机制就能够保证。restful

        其次,事务比较常见的是加在controller层,至于缘由嘛?有的开发工程师认为既然一次请求就是一次事务,把事务加在controller彷佛看起来也是没毛病的。固然,这只是彷佛而已。架构

        咋一听起来,有一丝道理。仔细寻思,一次请求只是说终端对后台调用一次,并不意味着这一次调用仅仅只发生一次逻辑调用。好比一次简单的下订单请求,首先会查询数据库有无库存,而后修改对应商品的库存数量,同时增长一条订单信息,往MQ中投递一条通知短信,等等。不只仅是调用多个dao层,并且可能会有MQ的相关操做。一次请求不等于一次逻辑调用。而屡次逻辑调用意味着多张数据库表的数据会获得更新。假如其中某一个dao层或者cache层发生异常,这一次调用应该是失败,而且由数据库保证回滚的。第二个理由是,controller因为是跟web容器绑定在一块儿的,由容器决定每一次请求是否开启线程进行响应,并且线程的容量也跟容器息息相关。因此尽量保证线程高效,而事务会开启另一个单独的线程,线程调度之间若是出现异常,那么事务可能会失控。第三个理由是,controller可能只针对restfull接口,若是对于常规RPC接口,直接开放service的,那么事务会直接不生效致使业务不知足。app

       一般状况下,通常的研发团队都会把事务拦截放在service来进行出来,而service中的每个方法由spring aop进行事务保证。只要在一个事务环境中,必定能保证ACID,service层的方法中要把一次方法的调用放在一块儿,能够是直接调用dao层,也能够是调用service层。不论是从未来的可扩展性(即便直接将service暴露给rpc接口,事务依然生效),仍是单一职责(一次操做由一个方法进行保障)。推荐将事务操做都放在service层进行统一处理。分布式

        对于一些小项目,对于controller和service没有特别明显的区别,甚至有的模块能够直接把service的逻辑实现直接放在controller中,这也不是什么大问题,在项目初期,使用人数很少,业务够简单,逻辑清晰的状况下,这也无伤大雅,若是随着项目的复杂度上升,业务逻辑加大,建议仍是把事务的控制从controller层移到servcie。线程

       小调查,各位朋友所在的开发项目组,对于事务是放在哪一层呢?能够留言交流。rest