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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3155591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:05:14  来源:igfitidea点击:

How to programmatically get transaction manager in a thread?

springjpatransactionswicketdao

提问by smallufo

I have a wicket page , which contains two Spring-managed beans , one is DAO , another is Service Object :

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

public class MergeAccountsPage extends WebPage
{
  @SpringBean
  private MergeEmailDao mergeEmailDao;

  @SpringBean
  private MergingService mergingService;
}

The MergingService's implementation's methods are mostly annotated with @Transactional, so every action involving MergingService works fine.

MergingService的实现的方法主要有注解@Transactional,所以涉及MergingService每一个动作正常工作。

But the problem comes here :

但问题来了:

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(...);
  }
};

The link will call mergeAccoungDao.update(ma)to update a row in DB.

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

But the data is not updated to DB , I think it is because the DAO is not wrapped in @Transaction nor tx:adviceand aoptags.

但是数据没有更新到 DB ,我认为这是因为 DAO 没有包含在 @Transactiontx:adviceaop标签中。

I wonder is there a way to programmatically get the transaction manager , and manually open/close the transaction ?

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

Note: I can solve the problem by adding this code in spring's XML :

注意:我可以通过在 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>

So that the DAO's save/update/delete will work like a charm.

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

But I'd not like to add this config . Because in fact , the DAO extends an AbstractDao , and there are other DB/DAOs extend this AbstractDao :

但我不想添加这个 config 。因为实际上,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

Therefore , if this AbstractDAO's CRUD is "adviced" by this transactionManagerApp , other DAOs may have problem , because other DAOs may depend on txManagerForum , txManagerBank , txManagerUser ...etc.

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

Back to the problem , is there a way to programmatically get txManager ? Such as :

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

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

Or is there any better way to wrap a transaction to the DAO ?

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

Thanks a lot.

非常感谢。

回答by Abhinav Sarkar

You have to inject the transaction manager in the class you want to use it. You can use constructor or property based injection for it or use autowiring. One you get the transaction manger, you can use the programmatic transaction support in Spring to start and commit the transaction. Here is the sample code from Spring reference 2.5:

您必须在要使用它的类中注入事务管理器。您可以为其使用构造函数或基于属性的注入或使用自动装配。一拿到事务管理器,就可以使用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();
      }
    });
  }
}

See the referencefor more details.

有关更多详细信息,请参阅参考资料