| # 8. Transactions Probably you have already wondered how db4o handles concurrent access to a single database. Just as any other DBMS, db4o provides a transaction mechanism. Before we take a look at multiple, perhaps even remote, clients accessing a db4o instance in parallel, we will introduce db4o transaction concepts in isolation. ## 8.1. Commit and rollback You may not have noticed it, but we have already been working with transactions from the first chapter on. By definition, you are always working inside a transaction when interacting with db4o. A transaction is implicitly started when you open a container, and the current transaction is implicitly committed when you close it again. So the following code snippet to store a car is semantically identical to the ones we have seen before; it just makes the commit explicit.
`[storeCarCommit] Pilot pilot = new Pilot("Rubens Barrichello", 99); Car car = new Car("BMW"); car.Pilot = pilot; db.set(car); db.commit();`
`[listAllCars] ObjectSet result = db.get(typeof(Car)); listResult(result);`
OUTPUT: 1 BMW[Rubens Barrichello/99]/0

However, we can also rollback the current transaction, resetting the state of our database to the last commit point.

`[storeCarRollback] Pilot pilot = new Pilot("Michael Schumacher", 100); Car car = new Car("Ferrari"); car.Pilot = pilot; db.set(car); db.rollback();`

`[listAllCars] ObjectSet result = db.get(typeof(Car)); listResult(result);`

OUTPUT: 1 BMW[Rubens Barrichello/99]/0

## 8.2. Refresh live objects

There's one problem, though: We can roll back our database, but this cannot automagically trigger a rollback for our live objects.

`[carSnapshotRollback] ObjectSet result = db.get(new Car("BMW")); Car car = (Car)result.next(); car.Snapshot(); db.set(car); db.rollback(); Console.WriteLine(car);`

OUTPUT: BMW[Rubens Barrichello/99]/3

We will have to explicitly refresh our live objects when we suspect they may have participated in a rollback transaction.

`[carSnapshotRollbackRefresh] ObjectSet result=db.get(new Car("BMW")); Car car=(Car)result.next(); car.Snapshot(); db.set(car); db.rollback(); db.ext().refresh(car, int.MaxValue); Console.WriteLine(car);`

OUTPUT: BMW[Rubens Barrichello/99]/0

What is this ExtObjectContainer construct good for? Well, it provides some functionality that is in itself stable, but the API may still be subject to change. As soon as we are confident that no more changes will occur, ext functionality will be transferred to the common ObjectContainer API. We will cover extended functionality in more detail in a later chapter.
Finally, we clean up again.

`[deleteAll] ObjectSet result = db.get(typeof(Object)); while(result.hasNext()){ db.delete(result.next()); }`

## 8.3. Conclusion

We have seen how transactions work for a single client. In the next chapter we will see how the transaction concept extends to multiple clients, whether they are located within the same VM or on a remote machine.

## 8.4. Full source

`namespace com.db4o.f1.chapter5 { using System; using System.IO; using com.db4o; using com.db4o.f1; public class TransactionExample : Util { public static void Main(string[] args) { File.Delete(Util.YapFileName); ObjectContainer db=Db4o.openFile(Util.YapFileName); try { storeCarCommit(db); db.close(); db = Db4o.openFile(Util.YapFileName); listAllCars(db); storeCarRollback(db); db.close(); db = Db4o.openFile(Util.YapFileName); listAllCars(db); carSnapshotRollback(db); carSnapshotRollbackRefresh(db); } finally { db.close(); } } public static void storeCarCommit(ObjectContainer db) { Pilot pilot = new Pilot("Rubens Barrichello", 99); Car car = new Car("BMW"); car.Pilot = pilot; db.set(car); db.commit(); } public static void listAllCars(ObjectContainer db) { ObjectSet result = db.get(typeof(Car)); listResult(result); } public static void storeCarRollback(ObjectContainer db) { Pilot pilot = new Pilot("Michael Schumacher", 100); Car car = new Car("Ferrari"); car.Pilot = pilot; db.set(car); db.rollback(); } public static void carSnapshotRollback(ObjectContainer db) { ObjectSet result = db.get(new Car("BMW")); Car car = (Car)result.next(); car.Snapshot(); db.set(car); db.rollback(); Console.WriteLine(car); } public static void carSnapshotRollbackRefresh(ObjectContainer db) { ObjectSet result=db.get(new Car("BMW")); Car car=(Car)result.next(); car.Snapshot(); db.set(car); db.rollback(); db.ext().refresh(car, int.MaxValue); Console.WriteLine(car); } } }`

--
generated by Doctor courtesy of db4objects Inc.