我正在尝试将我的事务动态路由到 READ_WRITE 或 READ_ONLY 数据源。
但是在我的类中 TransactionRoutingDataSource 扩展了 AbstractRoutingDataSource
当我尝试获取 TransactionSynchronizationManager.isCurrentTransactionReadOnly() 的值时
它总是返回 false。
我已经尝试使用自定义注释设置上下文,但是上下文是在我想使用它之后设置的,以路由我的事务,任何人都可以帮助我吗?
只需在 TransactionRoutingDataSource 中获取信息即可解决我的问题。
我使用默认值(DataSourceType.READ_WRITE 和 DataSourceType.READ_ONLY)进行了测试,它有效,事务被路由到正确的数据库
交易路由数据源
package com.example.wsappsiav.MultipleDatabase.Configuration.Teste;
import com.example.wsappsiav.MultipleDatabase.Properties.DatabaseContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class TransactionRoutingDataSource extends AbstractRoutingDataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionRoutingDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
LOGGER.info("Routed to : " + DatabaseContextHolder.getEnvironment());
LOGGER.info("isReadOnly : " + isReadOnly);
return DatabaseContextHolder.getEnvironment();
}
}
读取ReplicaAspect
package com.example.wsappsiav.MultipleDatabase;
import com.example.wsappsiav.MultipleDatabase.Configuration.Teste.DataSourceType;
import com.example.wsappsiav.MultipleDatabase.Properties.DatabaseContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Aspect
@Component
public class ReadReplicaAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadReplicaAspect.class);
@Around("@annotation(com.example.wsappsiav.MultipleDatabase.annotations.UseReadReplica)")
public Object routeToReadReplica(ProceedingJoinPoint joinPoint) throws Throwable {
LOGGER.info("Setting database context to " + DataSourceType.READ_ONLY);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(true);
LOGGER.info("Transaction Mananger: " + TransactionSynchronizationManager.isCurrentTransactionReadOnly());
DatabaseContextHolder.set(DataSourceType.READ_ONLY);
return joinPoint.proceed();
}
}
客户服务
@Service
public class ClienteService {
@Autowired
private ClienteRepository clienteRepository;
@Transactional(readOnly = true, propagation = Propagation.MANDATORY)
@UseReadReplica
public List<Cliente> listarTodosClientes() {
return clienteRepository.findAll();}
副本数据源
package com.example.wsappsiav.MultipleDatabase.Configuration.replica;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface ReplicaDataSource {
}
日志
2024-05-14T10:13:08.676-03:00 INFO 15568 --- [ws-app-siav] [nio-8080-exec-1] c.e.w.M.C.T.TransactionRoutingDataSource : Routed to : null
2024-05-14T10:13:08.676-03:00 INFO 15568 --- [ws-app-siav] [nio-8080-exec-1] c.e.w.M.C.T.TransactionRoutingDataSource : isReadOnly : false
2024-05-14T10:13:08.868-03:00 INFO 15568 --- [ws-app-siav] [nio-8080-exec-1] c.e.w.M.ReadReplicaAspect : Setting database context to READ_ONLY
2024-05-14T10:13:08.868-03:00 INFO 15568 --- [ws-app-siav] [nio-8080-exec-1] c.e.w.M.ReadReplicaAspect : Transaction Mananger: true
2024-05-14T10:13:08.947-03:00 DEBUG 15568 --- [ws-app-siav] [nio-8080-exec-1] org.hibernate.SQL : select c1_0.id,c1_0.cliente_nome,c1_0.cpf_cnpj,c1_0.email,c1_0.endereco,c1_0.telefone from bd_siav.cliente c1_0
Hibernate: select c1_0.id,c1_0.cliente_nome,c1_0.cpf_cnpj,c1_0.email,c1_0.endereco,c1_0.telefone from bd_siav.cliente c1_0
应用程序属性
spring.aop.proxy-target-class=true
spring.jpa.properties.org.hibernate.flushMode = MANUAL
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
spring.jpa.hibernate.ddl-auto=none
spring.sql.init.mode=always
spring.sql.init.continue-on-error=true
解决了。 我删除了TransactionRoutingDataSource的配置,并添加
LazyConnectionDataSourceProxy lazyDateSource = new LazyConnectionDataSourceProxy(dataSource);
lazyDateSource.setReadOnlyDataSource(dataSourceReader);
我查看这个问题