Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am writing a routine which has the following form:

TRY A
IF no success, B
IF no success, RETRY A
IF no success, throw error

It's not trivial to extract either A or B into it's own routine, so what is most simple structure that will allow me to retry A without code duplication?

Currently, I have a do..while that allows N retries:

int retries = 1;

do {
    // DO A

    if ( /*success*/ ) {
        break;
    } else if (retries > 0)  {
        // DO B

        if ( /*success*/) {
            break;
        }
    } else {
        // throw Error
    }
} while (retries-- > 0);

This is ugly and not ideal as it implies that I might want to ever retry more than once, which I don't. I will have to use a loop, but there has to be a more simple way that I'm not seeing.

For context, this is code generated in Java, executing SQL statements to try an UPDATE first, then if no entry to update is found, INSERT, and if that command fails (concurrency, already created), try UPDATE again.

share|improve this question
1  
Database is good at guaranteeing atomic operations, and it supports if statements. Why can't an SQL stored procedure handle all of this? If two of them are being run, then one can do the work and another can NOOP, perhaps return some value. –  Job Dec 7 '11 at 2:38
2  
Also, I have a hard time to believe that DoA() and DoB() could not be their own methods. If the two methods depend on each other, then have an interface which forces implementations of DoA() and DoB(). Then, you can have a small class that implements both. The two methods can share the state with each other with properly synchronized members. I think that logic should be separate-able. Now, are you generating logic like this for various types of tables or is this limited to a finite number of cases? Or two methods can remain functional and communicate entirely through input parameters –  Job Dec 7 '11 at 2:58
    
@Job, the parts can't be easily extracted into their own methods without significantly increasing the complexity due to the need to close the resources involved in a finally block (PreparedStatement specifically). –  NickC Dec 7 '11 at 4:50
1  
@Job - Derp - Just gave it a try using Hand-e-Food's solution - turned out much cleaner than I thought. Just had to use separate try blocks. –  NickC Dec 7 '11 at 5:08
1  
dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html not an option? –  Inca Dec 21 '11 at 15:09
show 1 more comment

2 Answers

I've written this in C, so I can't guarantee that it'll cut-and-paste into Java.

If you're certain you want to retry DoA only once, use can use one line:

bool DoIt()
{
    return DoA() || DoB() || DoA();
}

bool DoA() { } // Return true if successful.

bool DoB() { } // Return true if successful.

If you want the option of more than one retry, use this loop.

bool DoIt(int retryLimit)
{
    if (DoA()) return true;
    for (int retries = 0; retries < retryLimit; retries++)
    {
        if (DoB()) return true;
        if (DoA()) return true;
    }
    return false;
}

Edit: If you really cannot make time to extract DoA and DoB, then try the following block. Remember that comments are your friend:

bool retry = false;
bool success = false;
do
{
    // Do A.
    success = // true or false
    if (success) break;

    // Attempt the above code twice and the below code once.
    if (retrying) break;
    retrying = true;

    // Do B.
    success = // true or false
    if (success) break;
}
if (success)
{
    // Celebrate.
}
else
{
    // Commiserate.
}
share|improve this answer
    
he claims it too difficult to isolate A in a method... so this wont work –  Morons Dec 7 '11 at 2:33
    
I just updated the question - I explained it wrong slightly. I actually want to skip the second A if B succeeds, but, given your code, that would easily change to return DoA() || DoB() || DoA(). I like that, although yes, it's not easily extracted to a method. –  NickC Dec 7 '11 at 2:36
    
@Renesis, I've added a third option that doesn't use funcitons. –  Hand-E-Food Dec 7 '11 at 23:11
add comment

Why don't you do a select to test if the row exists, as opposed to an updated with a failure test?

Then you can just either insert or update...

share|improve this answer
    
This may be naive, but because I want to do this with the fewest queries in the most common case, which is that the rows will exist. –  NickC Dec 7 '11 at 2:18
    
Well then, figure out how to wrap A in a method or duplcate your code. There is no other option. –  Morons Dec 7 '11 at 2:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.