草庐IT

java - 在 Spring 中为不同数据源设置事务的正确方法?

coder 2024-03-04 原文

我有一个应用程序需要连接到多个数据库。这是一个管理应用程序,主要用于管理不同数据库中的条目 - 我们不需要同时访问多个数据库,也不需要任何类型的分布式事务管理。

基本上,应用程序的一个区域允许您在数据库 A 中创建小工具,而应用程序的另一个区域允许您在数据库 B 中配置类似的小工具。

当只使用一个数据源时,我们已经设置了事务并完美地工作。配置如下所示:

<aop:config>
    <aop:pointcut id="companyServicePoint" 
          expression="execution(* com.company.service.CompanyService.*(..))" />

    <aop:advisor advice-ref="companyServiceTxAdvice"
         pointcut-ref="companyServicePoint"/>
</aop:config>

<tx:advice id="companyServiceTxAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!-- set propogation required on create methods, all others are read-only -->
        <tx:method name="create*" propagation="REQUIRED"/>
        <tx:method name="*" read-only="true" />
    </tx:attributes>
</tx:advice>

<bean id="txManager" 
   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

这会在 CompanyService 中的任何方法的任何执行上设置一个切入点并将事务建议与切入点相关联,切入点需要为名称以“create”开头的任何方法进行事务处理。交易建议与绑定(bind)到数据源的 TransactionManager 相关联。

添加第二个(或更多)数据源时,如何将相同的事务建议应用到其他数据源?由于AOP advice只能关联一个transactionManager,transactionManager只能关联一个dataSource,是否需要设置重复的transaction advice?

如果我为同一个切入点设置重复的事务建议,这是否意味着我的 CompanyService 中的任何方法调用接口(interface)将需要针对我的所有 数据源进行传播?

为了让我的最后一个问题更清楚一点,我将声明多个实现 CompanyService 的 bean。接口(interface),每个 bean 都有一个单独的 CompanyDAO访问他们各自的数据源。我担心这种方法将意味着当 companyService1 bean 被调用,事务建议将在 all 上触发companyService beans/dataSources。

我是不是用错了方法?

更新:我实际上已经测试了我上面谈到的配置(将两个顾问附加到同一个切入点),并在 CompanyService 的任一单独实例上调用任何方法。正如预期的那样,实现实际上确实在两个数据源上创建了新事务:

DEBUG company.serviceDataSourceTransactionManager - Creating new transaction with name [com.company.service.CompanyService.createCompany]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG company.serviceDataSourceTransactionManager - Acquired Connection [connection1 string here...] for JDBC transaction
...
DEBUG company.serviceDataSourceTransactionManager - Creating new transaction with name [com.company.service.CompanyService.createCompany]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG company.serviceDataSourceTransactionManager - Acquired Connection [connection2 string here...] for JDBC transaction
...
DEBUG company.serviceDataSourceTransactionManager - Rolling back JDBC transaction on Connection [connection1 string here...]
...
DEBUG company.serviceDataSourceTransactionManager - Rolling back JDBC transaction on Connection [connection2 string here...]

这似乎会在未来引起问题,因为 CompanyService实例只与单个数据源一起工作。

是否有更好的方法来配置我想要完成的目标?

最佳答案

是的,您需要一份重复的交易通知。请注意,在以下配置中,切入点表达式选择了特定的 CompanyService bean。

<bean id="companyService1" class="com.company.service.CompanyServiceImpl">
  <property name="companyDao">
    <bean class="com.company.service.CompanyDAO">
      <property name="dataSource" ref="dataSource1"/>
    </bean>
  </property>
</bean>

<aop:config>
  <aop:pointcut
      id="companyServicePoint1"
      expression="bean(companyService1)"/>
  <aop:advisor
      advice-ref="companyServiceTxAdvice1"
      pointcut-ref="companyServicePoint1"/>
</aop:config>

<tx:advice id="companyServiceTxAdvice1" transaction-manager="txManager1">
  <tx:attributes>
    <!-- set propogation required on create methods, all others are read-only -->
    <tx:method name="create*" propagation="REQUIRED"/>
    <tx:method name="*" read-only="true"/>
  </tx:attributes>
</tx:advice>

<bean
    id="txManager1" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource1"/>
</bean>

要配置另一个 CompanyService bean,您需要复制相同的详细样板。另一种在 Spring 中划分事务的方法是使用 TransactionProxyFactoryBean .它稍微不那么冗长,因为它使用父 bean 定义来配置子 bean 继承的公共(public)属性。

<bean
    id="baseTransactionProxy"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
    abstract="true">
  <property name="transactionAttributes">
    <props>
      <prop key="create*">PROPAGATION_REQUIRED</prop>
      <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
    </props>
  </property>
</bean>

<bean id="companyService1" parent="baseTransactionProxy">
  <property name="transactionManager" ref="txManager1"/>
  <property name="target">
    <bean class="com.company.service.CompanyServiceImpl">
      <property name="companyDao">
        <bean class="com.company.service.CompanyDAO">
          <property name="dataSource" ref="dataSource1"/>
        </bean>
      </property>
    </bean>
  </property>
</bean>

<bean
    id="txManager1" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource1"/>
</bean>

关于java - 在 Spring 中为不同数据源设置事务的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1472688/

有关java - 在 Spring 中为不同数据源设置事务的正确方法?的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  8. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  9. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  10. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

随机推荐