我有一个在使用 mybatis 的 Spring 框架上开发的 Java Web 应用程序。我看到数据源是在 beans.xml 中定义的。现在我也想添加一个辅助数据源作为备份。例如,如果应用程序无法连接到数据库并出现错误,或者如果服务器关闭,那么它应该能够连接到不同的数据源。 Spring 中是否有配置来执行此操作,或者我们必须在应用程序中手动对其进行编码?
我在 Spring boot 中看到了主要和次要符号,但在 Spring 中什么也没有。如果与主数据源的连接失败/超时,我可以通过连接到辅助数据源在创建/检索连接的代码中实现这些。但是想知道这是否可以通过仅在 Spring 配置中进行更改来实现。
答案 0 :(得分:0)
让我一一说清楚-
@Primary
注释,但没有 @Secondary
注释。@Primary
注释的用途与您所描述的不同。 Spring 不会以任何方式自动切换数据源。 @Primary
只是告诉 spring 使用哪个数据源,以防我们没有在任何事务中指定一个。有关这方面的更多详细信息 - https://www.baeldung.com/spring-data-jpa-multiple-databases现在,当一个数据源宕机时,我们如何实际切换数据源-
keepalived
之类的东西。这也是一个高度主观和有争议的话题,这里有很多事情需要考虑,比如我们能否承受复制延迟,是否有为每个主站运行的从站(因为那样我们也必须切换从站,因为旧主站的从站现在会被淘汰)同步等)如果您的数据库分布在各个区域,这将变得更加困难(阅读很棒)并且需要更多的工程、规划和设计。@SmartTransactional
以用于我们的演示。示例代码。虽然没有测试它-
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SmartTransactional {}
public class SomeServiceImpl implements SomeService {
@SmartTransactional
@Transactional("primaryTransactionManager")
public boolean someMethod(){
//call a common method here for code reusability or create an abstract class
}
}
public class SomeServiceSecondaryTransactionImpl implements SomeService {
@Transactional("secondaryTransactionManager")
public boolean usingTransactionManager2() {
//call a common method here for code reusability or create an abstract class
}
}
@Component
@Aspect
public class SmartTransactionalAspect {
@Autowired
private ApplicationContext context;
@Pointcut("@annotation(...SmartTransactional)")
public void smartTransactionalAnnotationPointcut() {
}
@Around("smartTransactionalAnnotationPointcut()")
public Object methodsAnnotatedWithSmartTransactional(final ProceedingJoinPoint joinPoint) throws Throwable {
Method method = getMethodFromTarget(joinPoint);
Object result = joinPoint.proceed();
boolean failure = Boolean.TRUE;// check if result is failure
if(failure) {
String secondaryTransactionManagebeanName = ""; // get class name from joinPoint and append 'SecondaryTransactionImpl' instead of 'Impl' in the class name
Object bean = context.getBean(secondaryTransactionManagebeanName);
result = bean.getClass().getMethod(method.getName()).invoke(bean);
}
return result;
}
}