我正在尝试使用spring类实现数据库读写分离(我使用了本教程)。
AbstractRoutingDataSource
我正在使用的应用程序是使用多值和连接池(hikari)。因此,我为每个租户创建了一个(主/副本数据源)
我就是这样创建数据源的
公共DataSource RoutingDatasource(String tenantId,String databaseMasterUrl,String databaseReplicaUrl,String user,String password) { RoutingDataSource routingDataSource =新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 ;
}代码编译得很好,但并没有真正切换上下文。事实上,在调试之后,问题是在设置事务之前请求了数据源。当事务最终被设置时,为时已晚,数据源已经被加载。
我怎么才能纠正这种行为?谢谢。
发布于 2019-11-06 09:11:58
为了解决这个问题,我必须在对事务进行诱捕之前定义要使用的数据库,因此我已经定义了一个过滤器(我正在使用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);
}此方法在调用任何@事务性方法之前运行,如果数据库是GET方法,则该方法正在切换数据库。
我删除了@事务性方法中的DbContext.setDbType(DbContext.DbType.REPLICA);和Dbcontext.reset()。
定义“不仅是获取urls部件”只是因为在我的应用程序中有一些get方法在内部进行更新,因此我检测到了这些urls,并将它们影响到主数据库。
发布于 2022-08-16 03:05:44
将spring.jpa.open-in-view设置为false
https://stackoverflow.com/questions/57694764
复制相似问题