事务,有点开发经验的人都应该知道事务。聊到事务,大家都在说spring事务,事务失效的场景,优化方案。或者分布式事务,XA,saga,TCC,可靠性消息,最大通知。这些东西,网上随便一搜一大堆,因此我就有点不想从这个角度写事务了,我们就从实际工作角度触发,聊聊我对事务的思考。
事务是保证一组数据库操作要么都成功,要么都失败的。但是,事务的使用同时也会导致性能的损耗。那么我们到底要不要使用事务呢?这应该是我们关注的点。一个小应用,没什么压力。那么使用事务的性能损耗,就可以忽略不计了。但一个复杂的系统,访问量很高的系统呢?这个性能损耗,就不得不考虑了。
spring事务
什么操作需要事务
回归到开发本质,无论是多么复杂的业务,业务逻辑且先不论,最终都是对数据库的CRUD。数据库对应的操作就是增删改查。既然事务是针对一组数据库操作的,那么数据库的操作组合起来有最多就16种:
查 | 增 | 删 | 改 | |
---|---|---|---|---|
查 | 查、查 | 查、增 | 查、增 | 查、增 |
增 | 增、查 | 增、增 | 增、删 | 增、改 |
删 | 删、查 | 删、增 | 删、删 | 删、改 |
改 | 改、查 | 改、增 | 改、删 | 改、改 |
我们依次来分析这16种情况就可以得到我们使用事务的场景。
事务主要针对数据库的修改操作的,因此对于查询操作,都可以不用考虑。剩下的我们依次来分析。分析出,当第一个操作执行后,第二个操作会不会失败即可。如果会失败,且失败后影响数据一致性了,那么就要使用事务。
我们来分析增删改可能失败的场景:
增:增加的数据不能满足数据库表的要求时会失败,比如:唯一索引冲突,不能为空的数据为空等等。这些应该是sql语句错误导致的。
删:删除操作一般是数据已经删除了,再去删除会失败。但不影响数据的一致性。
改:修改操作失败场景就多了,除了增加操作的失败场景,还会因为where条件未能查询到数据导致失败
首先我们先不考虑网络、数据库的突然宕机、服务突然挂掉、sql语句错误的情况。那么只有在后边的操作是修改的时候,才有必要使用事务。那就剩下了三种情况:增、改、删、改,改、改。如果考虑上网络、宕机、服务挂掉、sql语句错误的情况。那所有的除查询以外的操作都应该增加事务。
什么样的业务需要事务
有句玩笑话说,不考虑业务的架构都是耍流氓。随是玩笑,但是不管我们做什么,都应该要充分考虑业务,在技术与业务之间找到一个平衡点。那我们就要从业务方面触发考虑下要不要使用事务。
从业务出发,其实就一句话数据是否需要强一致性。如果不需要的话,我们就可以不使用事务。一些边缘的业务,我们可以通过日志告警,人工干预让数据保持一致。一些不重要的业务,可以使用check程序来保证数据的一致性。不管是日志告警,还是check程序,当数据不一致出现原因不是因非网络、宕机等导致的,这时候就应该看看我们的代码是不是写的有问题了。
从业务和技术的角度综合考虑,你就会知道到底该不该用事务了。
分布式事务
分布式事务的产生是因为因为微服务导致的多个数据库操作分散在不同的服务中。也应该遵循刚写的spring事务的使用原则。
微服务最重要的一个规范就是高内聚、低耦合。那一个请求调到一个微服务中来就应该尽可能的在这一个服务中操作完毕,所以服务的切分合理性很重要。但现在的业务越来越复杂,服务间的调用再正常不过了,所以必然会出现一组数据库操作分散在各个系统中的情况。这个时候我们就应该考虑分布式事务了。
首先,使用分布式事务,那就要求所有的服务都要支持分布式事务,这在一个公司中,如果开始的时候就已经规定好了或者后期改造好了,在开发新的功能时可以使用分布式事务。如果之前什么都没有,就可以考虑saga了。至于该使用什么分布式事务,这个首先看公司的统一规定。能满足自己的业务需求时,就使用公司统一规定的。不能满足的时候,在看用什么。