RoutingDataSource 不在事务上切换上下文
RoutingDataSource is not switching context on transactions
我正在尝试使用 spring class 实现数据库 read/write 分离(我使用了本教程)
AbstractRoutingDataSource
我正在处理的应用程序正在使用多线程和连接池 (hikari)。所以我为每个租户创建了一个(master/replica 数据源)
这就是我创建数据源的方式
public DataSource RoutingDatasource(String tenantId,
字符串 databaseMasterUrl,
字符串 databaseReplicaUrl,
字符串用户,
字符串密码){
final RoutingDataSource routingDataSource = new RoutingDataSource();
final DataSource masterDataSource = buildTargetDataSource(tenantId,
cachePrepStmtsValue,
prepStmtCacheSize,
prepStmtCacheSqlLimit,
databaseMasterUrl,
driverClass,
user,
password,
MASTER_DATASOURCE_PREFIX);
final DataSource replicaDataSource = buildTargetDataSource(poolName + tenantId,
cachePrepStmtsValue,
prepStmtCacheSize,
prepStmtCacheSqlLimit,
databaseReplicaUrl,
driverClass,
user,
password,
REPLICA_DATASOURCE_PREFIX);
final Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DbContext.DbType.MASTER, masterDataSource);
targetDataSources.put(DbContext.DbType.REPLICA, replicaDataSource);
routingDataSource.setTargetDataSources(targetDataSources);
routingDataSource.setDefaultTargetDataSource(masterDataSource);
routingDataSource.afterPropertiesSet();
return routingDataSource;
}
上下文是这样决定的
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContext.getDbType();
}
这就是我告诉事务切换上下文的方式
@Transactional(readOnly = true)
public Opportunite consulter(UUID personUuid) {
DbContext.setDbType(DbContext.DbType.REPLICA);
//some work
DbContext.reset();
return some_result ;
}
代码编译正常,但并未真正切换上下文。事实上,在调试之后,问题是在设置事务之前请求了数据源。当事务最终设置时,为时已晚,数据源已经加载。
我该如何解决这个问题?谢谢。
为了解决这个问题,我必须在进入事务之前定义要使用的数据库,我已经定义了一个过滤器(我正在使用 spring)
public class DbFilter extends {
//les urls that do not only GET method
private final static String NOT_ONLY_GET_URL= "/api/parametre";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException, RestException {
DbContext.setDbType(DbContext.DbType.MASTER);
if (!NOT_ONLY_GET_URL.equals(request.getRequestURI()) && request.getMethod().equals("GET")) {
DbContext.setDbType(DbContext.DbType.REPLICA);
}
filterChain.doFilter(request, response);
}
此方法在调用任何@transactional 方法之前运行,如果是GET 方法则正在切换数据库。
我已经删除了
DbContext.setDbType(DbContext.DbType.REPLICA);和@transactional方法中的Dbcontext.reset()。
"not only get urls parts" 之所以被定义,是因为在我的应用程序中有一些 get 方法在内部进行更新,所以我检测到这些 url 并将它们影响到主数据库。
我正在尝试使用 spring class 实现数据库 read/write 分离(我使用了本教程)
AbstractRoutingDataSource
我正在处理的应用程序正在使用多线程和连接池 (hikari)。所以我为每个租户创建了一个(master/replica 数据源)
这就是我创建数据源的方式
public DataSource RoutingDatasource(String tenantId, 字符串 databaseMasterUrl, 字符串 databaseReplicaUrl, 字符串用户, 字符串密码){ final RoutingDataSource routingDataSource = new RoutingDataSource();
final DataSource masterDataSource = buildTargetDataSource(tenantId,
cachePrepStmtsValue,
prepStmtCacheSize,
prepStmtCacheSqlLimit,
databaseMasterUrl,
driverClass,
user,
password,
MASTER_DATASOURCE_PREFIX);
final DataSource replicaDataSource = buildTargetDataSource(poolName + tenantId,
cachePrepStmtsValue,
prepStmtCacheSize,
prepStmtCacheSqlLimit,
databaseReplicaUrl,
driverClass,
user,
password,
REPLICA_DATASOURCE_PREFIX);
final Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DbContext.DbType.MASTER, masterDataSource);
targetDataSources.put(DbContext.DbType.REPLICA, replicaDataSource);
routingDataSource.setTargetDataSources(targetDataSources);
routingDataSource.setDefaultTargetDataSource(masterDataSource);
routingDataSource.afterPropertiesSet();
return routingDataSource;
}
上下文是这样决定的
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContext.getDbType();
}
这就是我告诉事务切换上下文的方式
@Transactional(readOnly = true)
public Opportunite consulter(UUID personUuid) {
DbContext.setDbType(DbContext.DbType.REPLICA);
//some work
DbContext.reset();
return some_result ;
}
代码编译正常,但并未真正切换上下文。事实上,在调试之后,问题是在设置事务之前请求了数据源。当事务最终设置时,为时已晚,数据源已经加载。
我该如何解决这个问题?谢谢。
为了解决这个问题,我必须在进入事务之前定义要使用的数据库,我已经定义了一个过滤器(我正在使用 spring)
public class DbFilter extends {
//les urls that do not only GET method
private final static String NOT_ONLY_GET_URL= "/api/parametre";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException, RestException {
DbContext.setDbType(DbContext.DbType.MASTER);
if (!NOT_ONLY_GET_URL.equals(request.getRequestURI()) && request.getMethod().equals("GET")) {
DbContext.setDbType(DbContext.DbType.REPLICA);
}
filterChain.doFilter(request, response);
}
此方法在调用任何@transactional 方法之前运行,如果是GET 方法则正在切换数据库。
我已经删除了 DbContext.setDbType(DbContext.DbType.REPLICA);和@transactional方法中的Dbcontext.reset()。
"not only get urls parts" 之所以被定义,是因为在我的应用程序中有一些 get 方法在内部进行更新,所以我检测到这些 url 并将它们影响到主数据库。