Rails事务中加入非数据库操作:是否需移出?性能影响解析
Rails事务中非数据库步骤的性能优化问题
要不要把非数据库步骤移出事务?
必须移。哪怕执行顺序不影响最终结果,把非DB操作留在事务里纯粹是给自己找麻烦——会无端拉长事务的持有时间,带来没必要的性能损耗和潜在风险。
性能影响到底有多大?
得看你的non_db_step是啥操作:
- 如果只是简单的内存计算、字符串拼接这类快得离谱的操作,那性能影响可能微乎其微,几乎感觉不到;
- 但要是涉及调用外部API、读写文件、复杂数据运算这类耗时操作,那影响就非常明显了:
- 事务开着的时候,数据库会锁定你操作过的行甚至表(具体看隔离级别和操作类型),其他请求要碰这些数据就得等着,直接拖低系统的并发能力;
- 长事务会让数据库的日志写入压力变大,还更容易触发事务超时、死锁这些问题;
- 数据库连接会被这个事务占着不放,连接池很容易被耗尽,新请求进来就得等连接,系统整体响应速度会越来越慢。
Rails事务的底层逻辑
Rails的ActiveRecord::Base.transaction其实就是对数据库原生事务的一层封装:
- 进入事务块后,所有数据库操作都共享同一个事务上下文,块顺利执行完就自动提交,要是中间抛异常就自动回滚;
- 它会根据你用的数据库适配器(比如PostgreSQL、MySQL)来适配不同的事务特性,比如PostgreSQL会在事务启动时拍个数据快照,MySQL则按隔离级别控制数据可见性;
- 块里的非数据库操作不会触发任何数据库层面的逻辑,但会占着事务的执行时间,让事务“活”得更久。
优化后的代码示例
既然顺序不影响结果,直接把非DB步骤挪到事务外面就行,两种方式都可以:
# 方式一:先执行非DB操作,再跑事务 non_db_step ActiveRecord::Base.transaction do db_step db_step end
# 方式二:先跑完事务,再执行非DB操作 ActiveRecord::Base.transaction do db_step db_step end non_db_step
内容的提问来源于stack exchange,提问作者Omar Fareed
相关产品推荐
相关产品推荐

