好的,我想要完成的是以下内容:
在java企业bean中,我想将文件移动到另一个目录,除非数据库操作失败(即,我想将文件的正确位置存储在数据库中。现在,如果事务中出现问题,那么&如果我已经移动了文件,我的数据库会指向文件的错误位置。不好。)。
我尝试使用事务阶段AFTER_SUCCESS通过观察方法触发事件来移动文件。到现在为止还挺好。但是文件移动也可能失败(也许我无法访问目标目录或类似的东西),我也想把这个失败写入数据库。不幸的是,似乎观察者方法没有为我提供事务,我的方法调用失败。
从观察方法调用服务方法的想法是不是很糟糕?或者我做错了吗?
答案 0 :(得分:0)
通常,您应首先使用事务资源,然后使用非事务性资源。原因是您可以回滚事务资源,但不能回滚非事务性资源。
我的意思是:如果您能够更新数据库中的行,然后尝试移动文件并且失败,则可以安全地回滚数据库更新。但是,如果您移动文件并且它成功,但由于某种原因您无法更新数据库 - 您无法回滚移动的文件。
在您的特定情况下,我建议不要实际移动文件,而是复制它。因此,在数据库中,您将始终拥有新副本的实际位置。在不同的线程中,您可以以某种方式删除旧副本。您需要使用副本,因为移动实际文件时可能会抛出IOException
,而当您在数据库中回滚事务时,最终会出现错误的旧位置。尝试使用这种方法(使用EJB
容器管理的事务;您可以安全地找到Spring的变体):
@TransactionAttribute(REQUIRED)
void move(String newLocation, int fileId) throws CouldNotMoveException, DatabaseException {
try {
database.updateFileLocation(fileId, newLocation);
} catch (Exception exc) {
throw new DatabaseException(exc);
}
try {
file.copyFile(fileId, newLocation);
} catch (IOException exc) {
throw new CouldNotMoveException(exc);
}
}
您需要创建这样的异常才能回滚事务(或者只使用RuntimeException
- 检查容器上有关对异常和回滚策略做出反应的文档):
@ApplicationException(rollback = true)
public class DatabaseException extends Exception {
// omited
}
@ApplicationException(rollback = true)
public class CouldNotMoveException extends Exception {
// omited
}
在这里,您的客户端代码可以对CouldNotMoveException
做出反应并在数据库中写入错误的移动,这样您就可以满足您的要求。