【问题标题】:Primary/secondary datasource failover in Spring MVCSpring MVC 中的主/从数据源故障转移
【发布时间】:2021-05-01 04:59:30
【问题描述】:

我有一个使用 mybatis 在 Spring 框架上开发的 java web 应用程序。我看到数据源是在 beans.xml 中定义的。现在我也想添加一个辅助数据源作为备份。例如,如果应用程序无法连接到数据库并出现错误,或者服务器关闭,那么它应该能够连接到不同的数据源。 Spring 中是否有配置来执行此操作,或者我们必须在应用程序中手动编写代码?

我在 Spring boot 中看到了主要和次要符号,但在 Spring 中什么也没看到。如果与主数据源的连接失败/超时,我可以在创建/检索连接的代码中通过连接到辅助数据源来实现这些。但想知道这是否可以通过仅在 Spring 配置中进行更改来实现。

【问题讨论】:

  • 这是个好问题。
  • 我决定为此启动 50 声望赏金。

标签: spring database spring-mvc mybatis failover


【解决方案1】:

让我一一澄清-

  • Spring Boot 有 @Primary 注释,但没有 @Secondary 注释。
  • @Primary 注释的用途不是您所描述的。 Spring 不会以任何方式自动切换数据源。 @Primary 只是告诉 spring 使用哪个数据源,以防我们在任何事务中没有指定一个数据源。有关此的更多详细信息-https://www.baeldung.com/spring-data-jpa-multiple-databases

现在,当一个数据源出现故障时,我们如何实际切换数据源-

  • 大多数人在代码中管理这种高可用性。人们通常更喜欢保持同步的主动-被动模式下的 2 个主数据库实例。对于自动故障转移,可以使用 keepalived 之类的东西。这也是一个高度主观和有争议的话题,这里有很多事情需要考虑,比如我们能否承受复制延迟,每个主服务器是否有从服务器运行(因为那时我们也必须切换从服务器,因为旧主服务器的从服务器现在会出局同步等)如果您的数据库分布在各个地区,这将变得更加困难(读起来很棒),并且需要更多的工程、规划和设计。
  • 现在,问题特别提到为此使用应用程序代码。你可以做一件事。 我不建议在生产中使用它。永远。您可以使用自己的自定义注释围绕所有主要事务方法创建 ASPECTJ 建议。让我们将此注释称为 @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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 2010-11-06
    • 2016-05-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多