【问题标题】:Reusing same @Transactional method for different DataSources (JdbcTemplate) in Spring在 Spring 中为不同的 DataSource(JdbcTemplate)重用相同的 @Transactional 方法
【发布时间】:2021-05-28 23:39:16
【问题描述】:

我们有这段代码,其中相同的service 方法将调用不同的daos,每个使用不同的datasource(和不同的JdbcTemplates)。我们想使用@Transactional 注解,但据我所知,这个注解总是链接到特定的TransactionManager(因此,链接到特定的DataSource)。

所以,我的问题是,有没有办法在调用@Transactional 方法时动态选择使用哪个DataSource(或TransactionManager),以便我可以重用该方法来攻击不同的数据库?

【问题讨论】:

  • 如果您希望它与不同的数据源一起工作,也许它不应该使用声明性事务管理?您想重用该方法,但这并不意味着使用@Transactional 的硬性要求,是吗?
  • 是的,你是对的,没有。我们可以使用PlatformTransactionManager 并使用程序化事务,但我想知道是否存在“声明性”的可能性。
  • 好吧,SpEL 本来可以成为你的救星,但注释不是 support it,或者它......那是从 2013 年开始的?不...不支持。
  • 但我没有看到不使用程序化事务的理由。这是你需要额外控制的地方(与@Transactional 的易用性相比),只要确保你写得漂亮、干净、可维护和有据可查。
  • @didgewind 这个另一个question 可以为您指明正确的方向

标签: java spring transactions


【解决方案1】:

@Transactional 注释不允许value 属性的dynamic evaluation 选择TransactionManager(可能是设计使然,至少它看起来不会很快改变)。所以你不能有像@Transactional("#{@getTxManager}") 这样会在调用时解决 tx 管理器的东西。

在简单的情况下,您可能能够摆脱以下情况,但只有当您有一个主要 DS 和一个仅在某些情况下使用的辅助 DS 时才值得考虑。否则你会在调用foo/bar 之间选择代码,这看起来根本不干净

// TX boundary on the "top" abstraction layer
@Transactional("foo")
public void foo() {
    doWork();
}
@Transactional("bar")
public void bar() {
    doWork();
}

private void doWork() {
    // Work done here, no concern for tx management
}

对于多租户等更复杂的情况,如果您还没有考虑,AbstractRoutingDataSource 是一个简单而可靠的选择。虽然取决于您需要多少切换,但可能需要调整甚至不合适。

最后,您也许可以创建自己的注释来动态选择 DS(尽管我不保证会这样做),但这将是风险最高的方法,可能收获甚微。

【讨论】:

    【解决方案2】:

    对您来说最安全的方法是为每个 dao 创建单独的服务...我不想调试这样的代码。考虑维护此代码以及可能发生的故障。

    如果我是你,我会问自己以下问题:

    1.) 为什么要分开 dbs?

    2.) 上下文不是以某种方式混淆了吗?也许在他们之间建立一些界限?

    3.) 我的查询真的需要是事务性的吗?

    我可能不知道您的问题的背景,但对我来说,您似乎以错误的方式为您的应用程序建模,我会专注于它。

    【讨论】:

    • 如果应用程序需要在给定的数据库上做一些完全通用的事情怎么办?那么你不可能为此创建多个服务,因为你并不真正知道你在使用什么
    • “我的查询真的需要事务性的吗?”您是否建议您省略 @Transactional 属性和事务边界?这个答案的问题多于答案。
    • 我见过很多不需要事务的解决方案,只是在调试时才引起问题。此外,其中一些微服务甚至不需要事务数据库。
    • 你不必担心调试 OP 的代码,也没有提到微服务。您似乎在这里假设太多了。如果您在调试交易时遇到问题,也许您只是不了解交易?
    • @Skoq95 具有默认传播的标准@Transactional 会加入现有事务(如果存在),因此除非您使用Propagation.NESTED,否则没有嵌套事务(老实说,这可能在遗留代码中,我也不会创建过于复杂的事务边界)。无论使用什么工具,糟糕的开发人员都可能导致问题,而且这永远都不好笑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多