如何以编程方式在线程中获取事务管理器?
我有一个 wicket 页面,其中包含两个 Spring 管理的 bean,一个是 DAO,另一个是服务对象:
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:advice
和 aop
标签中。
我想知道是否有一种方法可以以编程方式获取事务管理器,并手动打开/关闭事务?
注意:我可以通过在 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?
多谢。
I have a wicket page , which contains two Spring-managed beans , one is DAO , another is 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.
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.
But the data is not updated to DB , I think it is because the DAO is not wrapped in @Transaction nor tx:advice
and aop
tags.
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 :
<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.
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 :
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.
Back to the problem , is there a way to programmatically get txManager ? Such as :
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 ?
Thanks a lot.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您必须将事务管理器注入到要使用它的类中。您可以使用构造函数或基于属性的注入,或者使用自动装配。
一旦获得事务管理器,就可以使用 Spring 中的编程事务支持来启动和提交事务。以下是 Spring 参考 2.5 中的示例代码:
请参阅 参考了解更多详情。
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:
See the reference for more details.