You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails多租户场景下调用Member领域类出现PooledConnection已关闭问题

问题根本原因
  • 注解作用顺序冲突:@CurrentTenant 注解加在控制器上,会在每次租户领域类操作完成后自动释放对应租户数据源连接,但 GroupService 加了类级别的 @Transactional 注解,默认会持有同一个连接贯穿整个服务调用周期,getMember() 执行完毕后连接被租户管理器提前释放,updateMember() 再复用该连接就会抛出关闭错误。
  • 多数据源事务配置缺失:你配置了多个分片数据源,但没有给租户领域类 Member 绑定数据源路由规则,也没有给服务方法匹配对应租户数据源的事务管理器,导致事务管理器持有的连接和租户路由拿到的连接不是同一个,单次操作完成后连接直接被回收。
  • 连接参数冲突:JDBC 配置里的 relaxAutoCommit=true 参数会打乱 Grails 默认的事务提交/回滚逻辑,多租户场景下极易导致连接被提前标记为无效并释放。
修复步骤

1. 调整注解作用位置和事务边界

把 @CurrentTenant 注解移到 Service 层,保证租户连接管理逻辑包裹在事务边界内,不会被提前释放,控制器层移除该注解即可:

// 调整后的控制器
class GroupController{
 def save(){
   groupService.getMember()
   groupService.updateMember()
 }
}
// 调整后的服务
@CurrentTenant
@Transactional
class GroupService{
 def getMember(){
   return Member.createCriteria().list{
     eq('customer','test')
   }
 }

 def updateMember(){
   Member.executeUpdate("Update member set group='testGroup'")
 }
}

2. 修正JDBC连接参数

移除所有数据源配置里的 relaxAutoCommit=true 参数,避免和 Spring 事务的连接状态管理逻辑冲突,调整后的配置如下:

dataSource:
  pooled: true
  driverClassName: com.mysql.cj.jdbc.Driver
  #dbCreate: "update"
  url: jdbc:mysql://localhost:3306/index?zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false
  username: root
  password: root
  properties:
    initialSize: 5
    maxActive: 100
    minIdle: 5
    maxIdle: 25
    maxWait: 10000
    maxAge: 10 * 60000
    timeBetweenEvictionRunsMillis: 1800000
    minEvictableIdleTimeMillis: 1800000
    validationQuery: "SELECT 1"
    validationInterval: 15000
    testWhileIdle: true
    testOnBorrow: true
    testOnReturn: false
    jdbcInterceptors: ConnectionState
    defaultTransactionIsolation: java.sql.Connection.TRANSACTION_READ_COMMITTED
dataSources:
  shard1:
    url: jdbc:mysql://localhost:3306/shard1?zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false
    dbCreate: none
  shard2:
    url: jdbc:mysql://localhost:3306/shard2?zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false
    dbCreate: none

3. 补充多租户事务配置(多数据源租户场景必填)

如果 Member 是绑定租户的分片表,需要在 application.yml 里配置租户专用事务管理器,保证事务和租户数据源正确绑定:

grails:
  gorm:
    multiTenancy:
      mode: DATABASE
      tenantResolverClass: 你的租户解析类全路径
    dataSources:
      shard1:
        transactionManager: tenantTransactionManager
      shard2:
        transactionManager: tenantTransactionManager

内容的提问来源于stack exchange,提问作者Rishav Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 15:06:02