Saturday, June 14, 2008

Don't use BeginTransactiion within a transaction.

Running Java code the other day I ran into a strange issue. My mock unit tests all worked, so I deployed a change to test, but when I ran test, it didn't work. The real thing acted differently than my mock did.

It took me nearly two hours to track the problem down, and it was strange enough that I had to resort to stepping through Java code. I prefer to find where things fail with the logging statements.

My error was with this (psuedo-code):


UpdateRecord(Record record, boolean updateRelated ) {

beginTransaction;
updateRecordInDB(record);
if( updateRelated ) {
Collection related = getRelated();
foreach(relatedRecord in related) {
UpdateRecord(relatedRecord, false); // recursive call
}
}
endTransaction;
}


When the beginTransaction was called within the recursive call, the Connection threw an error.

The solution was to remove the recursion.

UpdateRecord(Record record, boolean updateRelated ) {

beginTransaction;

insertRecordIntoDB(record);
if( updateRelated ) {
Collection related = getRelated();
foreach(relatedRecord in related) {
insertRecordIntoDB(record);
}
}
endTransaction;
}

insertRecordIntoDB(record) {
// do some important stuff.
updateRecordInDB(record);
}


That refactor allowed me to not duplicate code, and let me only call beginTransaction once, so all related records were updated within the same transaction.

No comments: