如何以编程方式在线程中获取事务管理器?

Posted

技术标签:

【中文标题】如何以编程方式在线程中获取事务管理器?【英文标题】:How to programmatically get transaction manager in a thread? 【发布时间】:2011-03-10 11:52:02 【问题描述】:

我有一个检票口页面,其中包含两个 Spring 管理的 bean,一个是 DAO,另一个是 Service Object:

public class MergeAccountsPage extends WebPage

  @SpringBean
  private MergeEmailDao mergeEmailDao;

  @SpringBean
  private MergingService mergingService;

MergingService 的实现方法大多用 @Transactional 注释,因此涉及 MergingService 的每个操作都可以正常工作。

但问题来了:

Link<Void> link = new Link<Void>("cancelLink") 
  @Override
  public void onClick()  
    ma.setNewEmail(null);
    ma.setNewEmailClicked(null);
    ma.setNewEmailSentTime(null);
    mergeAccoungDao.update(ma); //not written to DB
    setResponsePage(...);
  
;

该链接将调用mergeAccoungDao.update(ma) 来更新数据库中的一行。

但是数据没有更新到 DB ,我认为是因为 DAO 没有被包裹在 @Transaction 或者 tx:adviceaop 标签中。

我想知道有没有办法以编程方式获取事务管理器,并手动打开/关闭事务?

注意:我可以通过在spring的XML中添加这段代码来解决这个问题:

  <tx:advice id="txAdviceApp" transaction-manager="transactionManagerApp">
    <tx:attributes>
      <tx:method name="get*"    read-only="true"/>
      <tx:method name="save*"   propagation="REQUIRED"/>
      <tx:method name="update*" propagation="REQUIRED"/>
      <tx:method name="delete*" propagation="REQUIRED"/>
      <tx:method name="*" propagation="SUPPORTS"/>
    </tx:attributes>
  </tx:advice>

  <aop:config>
    <aop:pointcut id="methods" expression="execution(* destiny.utils.AbstractDao+.*(..))"/>
    <aop:advisor advice-ref="txAdviceApp" pointcut-ref="methods"/>
  </aop:config>

这样 DAO 的保存/更新/删除将像一个魅力一样工作。

但我不想添加这个配置。因为实际上DAO扩展了一个AbstractDao,还有其他DB/DAO扩展了这个AbstractDao:

public interface AbstractDao<T> 
  public T get(Serializable id);
  public T save(T t);
  public T update(T t);
  public void delete(T t);


public abstract class AbstractDaoJpaImpl<T> implements AbstractDao<T>

public interface MergeAccountDao extends AbstractDao<MergeAccount>

@Repository
public class MergeAccountDaoImpl extends AbstractDaoJpaImpl<MergeAccount> implements MergeAccountDao

因此,如果这个 AbstractDAO 的 CRUD 被这个 transactionManagerApp “建议”,其他 DAO 可能有问题,因为其他 DAO 可能依赖于 txManagerForum 、 txManagerBank 、 txManagerUser ...等。

回到问题,有没有办法以编程方式获取 txManager ?如:

TransactionManager txManager = TxManagerThreadLocal.get();
txManager.begin();
ma.setNewEmailSentTime(null);
mergeAccoungDao.update(ma); 
txManager.commit();

或者有没有更好的方法将交易打包到 DAO 中?

非常感谢。

【问题讨论】:

【参考方案1】:

您必须在要使用的类中注入事务管理器。您可以使用构造函数或基于属性的注入或使用自动装配。 获得事务管理器后,您可以使用 Spring 中的编程事务支持来启动和提交事务。这是 Spring 参考 2.5 中的示例代码:

public class SimpleService implements Service 

  // single TransactionTemplate shared amongst all methods in this instance
  private final TransactionTemplate transactionTemplate;

  // use constructor-injection to supply the PlatformTransactionManager
  public SimpleService(PlatformTransactionManager transactionManager) 
    Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
    this.transactionTemplate = new TransactionTemplate(transactionManager);
  

  public Object someServiceMethod() 
    return transactionTemplate.execute(new TransactionCallback() 

      // the code in this method executes in a transactional context
      public Object doInTransaction(TransactionStatus status) 
        updateOperation1();
        return resultOfUpdateOperation2();
      
    );
  

有关详细信息,请参阅reference。

【讨论】:

以上是关于如何以编程方式在线程中获取事务管理器?的主要内容,如果未能解决你的问题,请参考以下文章

如何以与在 Windows 资源管理器中“发送给邮件收件人”相同的方式以编程方式发送电子邮件?

是否可以在资源管理器窗口中以编程方式将文件夹添加到 Windows 10 快速访问面板?

在recyclerview android中以编程方式更改布局管理器

如何以编程方式获取 TaskManager 进程 CPU 使用率(不是 PerfMon API)

Python,Chrome 任务管理器 - 以编程方式访问 Chrome 任务管理器的文本而不使用 CHROMIUM

如何以编程方式获取 Xcode 显示的线程名称