Search code examples
javasqloraclejdbcatomic

JDBC guarantee atomic operation via executeBatch call within PreparedStatement


I have the following domain object:

class Cat  
{  
    String name;  
    int age;  
}

and the following statement to do batch inserts of cats:

void insertBulkCats(Collection<Cat> cats)  
{  
    Connection conn = getConnection();  
    PreparedStatement statement = new PreparedStatement();  
    for(Cat cat : cats)  
    {  
       statement.setString(1, cat.getName());  
       statement.setInt(2, cat.getAge());
       statement.addBatch();
    }     
    statement.executeBatch();  
    PreparedStatement mergeStatement = conn.prepareStatement(MERGE_CATS);  
    mergeStatement.execute();
    PreparedStatement dropStatement = conn.prepareStatement(CLEAR_CATS);    
    dropStatement.execute();  
    conn.commit();
}  

This is an Oracle database. As the steps I want to perform are insert all cats, do a merge against my archived cats, then drop all records from the original cats that were inserted. My concern is that this approach above does not guarantee a rollback or a solitary operation to occur. My question is how do I guarantee that this executes all as one atomic operation? Additionally how can I guarantee that no other function touches the database (in terms of doing updates to the Cat table) that are not reads?


Solution

  • Atomicity is a feature of ACID DBMS. It is automatic in Oracle : run all your DML (update/insert/delete), once you are done issue a commit. You are guaranteed that the operations will be saved as an indivisible transaction (if the commit fails nothing is saved).

    In JDBC you have to make sure to turn off autocommit.

    Concerning concurrency, it is also an integrated feature of most DBMS, although the behaviours of locking can be different among major DBMS.

    In Oracle writes don't block reads, although other transactions won't see your changes until you have committed: this isolation is implemented via multi-versionning. The locking mechanism of DML is at the row level. Only one transaction can modify a row at the same time. A common pattern in Oracle for a unit of work would be:

    1. Select the rows you want to modify with the clause FOR UPDATE. This will put a lock on the rows and other transactions won't be able to modify these rows until you commit or rollback.
    2. Do all your DML without intermediate commit
    3. Commit on success or rollback in case of error.

    For further reading: more on transaction management, more on concurrency and locking.

    Locking a whole table is rare in Oracle, although it is a possibility. The LOCK TABLE command can be used to prevent any modification from other sessions to an entire table.