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
相关产品推荐
相关产品推荐

