开发者

What does RetryingTransactionHandler work within alfresco

Alfresco advise the programmer once you need to make a transaction into the repository to use RetryingTransactionHandler to achieve the transaction.

Can anyone give me a clarification bout that ?

specifically i'm talking about code like this

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(Operati开发者_如何转开发onTypes.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);
    }

Also, as you are notice i use AuthenticationUtils.runAs().

So can you help me to understand different keys in this code like RetryingTransaction & AuthenticationUtils ?


The RetryingTransactionHelper ensures the callback you provide is executed within a transaction. Moreover, as the name suggests, if the transaction fails for some reasons (e.g. an Exception is thrown in the callback code that's not properly caught, or you try to change the same content in the repository concurrently from two different threads), the same transaction will be properly rolled back and re-executed ("retried") a configurable amount of times (default: 20). This is handier than manually handling transactions more often than not.

In the code you posted, you are nesting the call to doProcessActionCallbackOperations.CreateOrganizationCallback in two transactions (because of the last parameter of doInTransaction being always true, i.e. requiresNew), the outer being created before callback gets executed, the inner the one created within the callback itself. It seems to me that you could get rid of the inner transaction, but that's up to you. Transactions can be nested, even though failures in an inner transaction will most likely invalidate the whole stack of transactions.

The AuthenticationUtils.runAs facility allows you to execute pieces of logic using an authority in general different from the current user. Internally, user credentials are stored as ThreadLocal parameters. In you case, the AuthenticationUtil.runAs takes care of temporarily change such ThreadLocal to allow the inner callback to always execute with the highest permission level (i.e. system) regardless of which user is executing the code. There are also situations where there's no logged in user currently set, e.g. within scheduled jobs. Then the AuthenticationUtils.runAs allows you to access the content into the repository, usually specifying system or admin users.


Just to clarify a little bit more, RetryingTransactionHelper will retry the operation only if the thrown exception is of a specific kind. Mainly exceptions related to being the loser in a concurrency situation:

 /**
 * 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
                };

I think that is enough with one of those transactions being in the exception stack, not necesarily the last one. I also think that you can avoid retries by putting an Exception that implements org.alfresco.repo.transaction.DoNotRetryException interface.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜