Actix-web 4.0 多并发请求下与PostgreSQL交互的隔离机制疑问
嘿,这个问题我太有共鸣了!之前也碰到过类似的测试差异情况,咱们一步步拆解为什么两种测试结果会不一样~
核心原因:Actix-web给每个HTTP请求都配了独立的数据库交互上下文
你直接用Rayon调用函数测试失败,但发真实HTTP请求测试通过,本质区别在于数据库连接的隔离性:
1. Actix-web的请求-连接绑定逻辑
在Actix-web + Diesel的常规配置里,你应该是用了连接池(比如r2d2或者Diesel自带的连接池)。Actix-web会为每个进来的HTTP请求,从连接池里分配独立的数据库连接——也就是说,用户A的请求用连接1,用户B的请求用连接2,两者完全互不干扰。
你代码里设置的SET SESSION myapp.user_id = '{user_id}'是绑定在当前数据库连接上的,不同连接的SESSION变量是各自独立的。所以用户A的连接1设置的user_id只会影响连接1上的查询,用户B的连接2完全不受影响,RLS自然能正确隔离数据。
2. 直接函数调用测试的问题所在
当你用Rayon直接调用insert或read函数时,大概率是把同一个PgConnection实例传给了多个并发执行的函数调用(哪怕你用了&mut,Rayon的并发调度可能会让不同线程的操作在同一个连接上交错)。这种情况下,多个请求会共享同一个数据库连接:
- 比如用户A刚把SESSION设为自己的ID,用户B的请求紧接着把同一个连接的SESSION改成了自己的ID,这时候用户A后续的插入/查询就会用到用户B的ID,导致数据串了。
要是你在直接测试时,给每个并发调用都从连接池里取独立的连接,测试结果肯定会和HTTP请求测试一致。
3. 事务的作用范围补充
再看你的insert函数,在事务里循环设置SESSION变量——这里要注意:事务是绑定在当前数据库连接上的,每个连接的事务是独立的。Actix-web里每个请求用独立连接,所以每个请求的事务不会和其他请求的事务交错执行,SESSION变量的修改只会在当前事务的连接内生效,不会“串”到其他请求里。
总结一下
Actix-web能保证多请求下的隔离性,关键是靠连接池为每个请求分配独立数据库连接,让每个请求与PostgreSQL的交互都在专属的连接上下文中进行,SESSION变量、事务都是隔离的。而你直接函数调用测试时没做好连接隔离,才导致了数据串读/串写的问题。
备注:内容来源于stack exchange,提问作者parmesant

