一旦您需要在存储库中创建事务以使用RetryingTransactionHandler来实现事务,Alfresco会建议程序员。
有人能给我一个澄清吗?
特别是我在谈论像这样的代码
RetryingTransactionCallback<String> callback = new RetryingTransactionCallback<String>(){
public String execute() throws Throwable {
// doProcess must be invoked within user context.
AuthenticationUtil.runAs(new RunAsWork<String>(){
public String doWork()throws Exception{
try {
if(getOperationType().equals(OperationTypes.CREATE_ORGANIZATION_OPERATION)){
RetryingTransactionHelper txnHelper =
Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
txnHelper.doInTransaction(doProcessActionCallbackOperations.CreateOrganizationCallback, false, true);
}
} catch(Throwable e){
}
return "";
}
}, AuthenticationUtil.getSystemUserName());
return "";
}
};
try {
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
txnHelper.doInTransaction(callback, false, true);
} catch (Throwable e) {
if (e instanceof ReportedException == false) {
Utils.addErrorMessage(formatErrorMessage(e), e);
}
ReportedException.throwIfNecessary(e);
}
此外,正如您所知,我使用AuthenticationUtils.runAs()。
那么你可以帮我理解这段代码中的不同键,如RetryingTransaction&amp; AuthenticationUtils?
答案 0 :(得分:5)
RetryingTransactionHelper
确保您提供的callback
在交易中执行。此外,顾名思义,如果事务因某些原因失败(例如,callback
代码中没有正确捕获异常,或者您尝试从两个不同的线程同时更改存储库中的相同内容) ,相同的事务将被适当地回滚并重新执行(“重试”)一段可配置的次数(默认值:20)。这比手动处理交易更容易。
在您发布的代码中,您在两个事务中将调用嵌套到doProcessActionCallbackOperations.CreateOrganizationCallback
(因为doInTransaction
的最后一个参数始终为true
,即requiresNew
) ,在callback
执行之前创建的外部,在callback
本身内创建的内部。在我看来,你可以摆脱内部交易,但这取决于你。事务可以嵌套,即使内部事务中的失败很可能使整个事务堆无效。
AuthenticationUtils.runAs
工具允许您使用与当前用户不同的权限来执行逻辑部分。在内部,用户凭据存储为ThreadLocal
个参数。在您的情况下,AuthenticationUtil.runAs
负责临时更改此类ThreadLocal
以允许内部回调始终以最高权限级别(即系统)执行,而不管哪个用户正在执行代码。还存在当前没有登录用户的情况,例如在预定的工作。然后,AuthenticationUtils.runAs
允许您访问存储库中的内容,通常指定system
或admin
个用户。
答案 1 :(得分:4)
为了澄清一点,RetryingTransactionHelper只有在抛出的异常属于特定类型时才会重试该操作。主要是与并发情况下的输家有关的例外:
/**
* Exceptions that trigger retries.
*/
@SuppressWarnings({ "rawtypes" })
public static final Class[] RETRY_EXCEPTIONS;
static
{
Class<?>[] coreClasses = new Class[] {
ConcurrencyFailureException.class,
DeadlockLoserDataAccessException.class,
StaleObjectStateException.class,
JdbcUpdateAffectedIncorrectNumberOfRowsException.class, // Similar to StaleObjectState
LockAcquisitionException.class,
ConstraintViolationException.class,
UncategorizedSQLException.class,
SQLException.class,
BatchUpdateException.class,
DataIntegrityViolationException.class,
StaleStateException.class,
TooManyResultsException.class, // Expected one result but found multiple (bad key alert)
ObjectNotFoundException.class,
CacheException.class, // Usually a cache replication issue
SQLGrammarException.class, // Actually specific to MS SQL Server 2005 - we check for this
LockTryException.class
};
我认为这足以让其中一个事务处于异常堆栈中,而不是最后一个事务。我还认为你可以通过放置一个实现org.alfresco.repo.transaction.DoNotRetryException
接口的异常来避免重试。