我正在使用Spring的@Transactional和Hibernate。 我试图将两个dao方法放入单个事务中,并希望回滚特定的Exception。 代码如下:
服务类方法:
@Transactional(propagation=Propagation.REQUIRES_NEW,value="txManager",rollbackFor=TransactionUnSuccessException.class)
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
Account account = null;
account = transferDao.makeTransaction(transaction, userName);
return account;
}
道方法:
@Repository
public class TransferDao extends HibernateDaoSupport {
@Autowired
private SessionFactory sessionFactory;
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
HibernateTemplate hibernateTemplate = getHibernateTemplate();
Account account = null;
Session session = hibernateTemplate.getSessionFactory().openSession();
//session.beginTransaction();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
//session.getTransaction().commit();
return account;
}
private void updateSelfAccount(Transaction transaction, String userName,
Session session) {
User currentUser = null;
System.out.println("TransferDao.updateSelfAccount()" + transaction);
Query query = session.createQuery("from User where userName=:userName");
query.setParameter("userName", userName);
currentUser = (User) query.list().get(0);
currentUser.getAccount().getTransactions().add(transaction);
currentUser.getAccount().setAvailableBalance(
currentUser.getAccount().getAvailableBalance()
- transaction.getAmount());
transaction.setTransAccount(currentUser.getAccount());
session.save(transaction);
session.update(currentUser.getAccount());
session.update(currentUser);
private Account updateAnotherAcccount(Transaction transaction,
Session session) throws TransactionUnSuccessException {
Account account = null;
try {
Query query = session
.createQuery("from Account where accNo=:accNo");
query.setParameter("accNo", transaction.getToAcc());
account = (Account) query.list().get(0);
if (account.getAvailableBalance() < 5000) {
account.setAvailableBalance(account.getAvailableBalance()
+ transaction.getAmount());
account.getTransactions().add(transaction);
transaction.setTransAccount(account);
session.save(transaction);
session.update(account);
} else {
throw new TransactionUnSuccessException();
}
} catch (TransactionUnSuccessException te) {
te.printStackTrace();
}
return account;
}
}
}
Xml配置:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
如果两个方法中的任何一个(updateSelfAccount,updateAnotherAcccount)失败,则整个事务应该回滚。 但它无法在给定的Exception上回滚,即使我不确定这是否只发生在单个事务中。 请纠正我。
答案 0 :(得分:3)
使用@Transactional注释的目的是您的代码不应该处理事务本身。在您的代码示例中,您使用@Transactional,因此您不必执行
之类的操作session.beginTransaction();
使用
正确设置弹簧的其他内容<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="dataSource"
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
通常,session中的sessionFactory是@Autowired并且可以轻松访问你所做的会话
sessionFactory.getCurrentSession()
最后一点你不需要有一个很大的try catch然后抛出你的TransactionUnSuccessException,默认情况下,事务会在任何异常时回滚。
答案 1 :(得分:0)
对于初学者,请不要使用HibernateTemplate
和/或HibernateDaoSupport
他们应被视为已弃用。直接使用SessionFactory
。接下来永远不要在Spring托管事务中使用openSession
因为这将打开新会话,而不是绑定到事务和spring之外。请改用getCurrentSession
上的SessionFactory
。
最后从不捕获并吞下异常,spring的TransactionInterceptor需要异常来决定做什么(回滚或提交)
重构你的DAO以包含所有这些。
@Repository
public class TransferDao {
@Autowired
private SessionFactory sessionFactory;
private Session getSession() {
sessionFactory.getCurrentSession();
}
public Account makeTransaction(Transaction transaction, String userName) throws TransactionUnSuccessException {
Account account = null;
Session session = getSession();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
return account;
}
从更新量来看,另一个观察是你有一个映射问题。当您的映射正确时,您只需要更新/保存User
对象,其他所有内容都应该自动保留。
另一个观察,你不应该绕过会话,只需调用getSession()
方法(我添加到dao中)。您应该在整个交易期间获得相同的Session
。
最后观察,您的dao似乎包含业务逻辑,而应该在服务方法中(例如,检查帐户余额)。