我的问题与交易和例外有关
要求:
我有10条记录要插入到数据库表中。插入每条记录后,我将数据插入另一个表中。因此,如果插入第二个表失败,我想回滚该记录。
实施例。 说一次处理10人的现金转账(从一个账户到账户)。
伪代码: ------------- EJB方法的开始
for(int i = 0; i < TransferRecords.length; i++)
{
try
{
//Deduct cash from TransferRecord.accountFrom --- Includes use of Hibernate Session
//Add cash in TransferRecord.accountTo -- Includes use of Hibernate Session
} catch(AppException exception)
{
//Rollback the transaction only for this particular transfer (i)
// But here when I go for next record it says session is closed
}
}
--------- EJB方法结束
这里使用@ApplicaitonException(rollback = true)annotion创建了AppException。
我们想要的功能是:即使TransferRecord的事务失败(比如说2),我希望为记录0,记录1,记录3,记录4(等等......)提交数据,但不是用于记录2)
但问题是:当TransferRecord 2失败时,当我转移到TransferRecord 3时,我收到“Session Closed”错误。
我的怀疑是: 这是正确的做法吗?或者我应该在EJB之外运行for循环(对于每个TransferRecord) 2.如何确保会话未关闭但事务已回滚(仅针对特定失败事务的事务)
提前谢谢。
我使用的是EJB3,Hibernate 3.x,Jboss 4.2.x,我正在使用容器管理事务。
答案 0 :(得分:2)
这是一种正确的方法吗?
不,使用CMT,您的方法是您的交易单位。所以这里,你所有TransferRecord
并在同一个唯一的交易中处理。
顺便问一下,你如何回滚交易?您传播RuntimeException
还是致电setRollbackOnly()
?我只是好奇。
或者我应该在EJB之外运行for循环(对于每个TransferRecord)?
为什么在外面?没有什么能迫使你这样做。如果要在自己的事务中处理每个TransferRecord
,则应将它们传递给另一个 EJB方法(下面的代码受this answer启发):
// supposing processRecords is defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
@EJB
private MyStatelessLocal1 myBean;
public void processRecords(List<TransferRecord> objs) {
// No transactional stuff so no need for a transaction here
for(Object obj : objs) {
this.myBean.process(obj);
}
}
@TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
public void process(TransferRecord transferRecord) {
// Transactional stuff performed in its own transaction
// ...
}
}
如何确保会话未关闭但事务已回滚(仅针对特定失败事务的事务)
我想我已经涵盖了这一部分。
答案 1 :(得分:1)
你在这里唯一的选择是使用用户事务而不是bean之外的循环容器管理事务,这样每次进入bean时你都会得到带有相关事务和连接的新实体管理器(基本上是会话)
答案 2 :(得分:0)
我认为您可以创建两个独立的事务,第一个用于TransferRecord(1)(一旦一切正常就执行提交),然后为所有TransferRecord(i + 1)启动其他TX。
另一种方法是使用保存点,能够回滚并丢弃通过该保存点的所有内容(但我更喜欢第一种方法)。
问候。