diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
index 0b949758d8dcf83fb2ffce6bfa6122d6c705f30a..b557bbaa907bb11a900340b45ce79cf75e042010 100644
--- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
+++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
@@ -45,8 +45,9 @@ public interface DatabaseComponent {
 
 	/**
 	 * Starts a new transaction and returns an object representing it.
+	 * @param readOnly true if the transaction will only be used for reading.
 	 */
-	Transaction startTransaction() throws DbException;
+	Transaction startTransaction(boolean readOnly) throws DbException;
 
 	/**
 	 * Ends a transaction. If the transaction is marked as complete, the
diff --git a/briar-api/src/org/briarproject/api/db/Transaction.java b/briar-api/src/org/briarproject/api/db/Transaction.java
index cb89f142ca3461582180f53f9ffb9e557e0cdc64..15297a5734cc0524345c679835f1212e7e029f86 100644
--- a/briar-api/src/org/briarproject/api/db/Transaction.java
+++ b/briar-api/src/org/briarproject/api/db/Transaction.java
@@ -12,12 +12,14 @@ import java.util.List;
 public class Transaction {
 
 	private final Object txn;
+	private final boolean readOnly;
 
 	private List<Event> events = null;
 	private boolean complete = false;
 
-	public Transaction(Object txn) {
+	public Transaction(Object txn, boolean readOnly) {
 		this.txn = txn;
+		this.readOnly = readOnly;
 	}
 
 	/**
@@ -28,6 +30,13 @@ public class Transaction {
 		return txn;
 	}
 
+	/**
+	 * Returns true if the transaction can only be used for reading.
+	 */
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+
 	/**
 	 * Attaches an event to be broadcast when the transaction has been
 	 * committed.
diff --git a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
index 40640c17ab397c780f6cd97ad0253ec3af946009..5c64dc98feba454d705a5703587f315c2d39bae2 100644
--- a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
+++ b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java
@@ -57,7 +57,7 @@ class ClientHelperImpl implements ClientHelper {
 	@Override
 	public void addLocalMessage(Message m, ClientId c, BdfDictionary metadata,
 			boolean shared) throws DbException, FormatException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			addLocalMessage(txn, m, c, metadata, shared);
 			txn.setComplete();
@@ -89,7 +89,7 @@ class ClientHelperImpl implements ClientHelper {
 	public BdfDictionary getMessageAsDictionary(MessageId m) throws DbException,
 			FormatException {
 		BdfDictionary dictionary;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			dictionary = getMessageAsDictionary(txn, m);
 			txn.setComplete();
@@ -112,7 +112,7 @@ class ClientHelperImpl implements ClientHelper {
 	public BdfList getMessageAsList(MessageId m) throws DbException,
 			FormatException {
 		BdfList list;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			list = getMessageAsList(txn, m);
 			txn.setComplete();
@@ -135,7 +135,7 @@ class ClientHelperImpl implements ClientHelper {
 	public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
 			throws DbException, FormatException {
 		BdfDictionary dictionary;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			dictionary = getGroupMetadataAsDictionary(txn, g);
 			txn.setComplete();
@@ -156,7 +156,7 @@ class ClientHelperImpl implements ClientHelper {
 	public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
 			throws DbException, FormatException {
 		BdfDictionary dictionary;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			dictionary = getMessageMetadataAsDictionary(txn, m);
 			txn.setComplete();
@@ -177,7 +177,7 @@ class ClientHelperImpl implements ClientHelper {
 	public Map<MessageId, BdfDictionary> getMessageMetatataAsDictionary(
 			GroupId g) throws DbException, FormatException {
 		Map<MessageId, BdfDictionary> map;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			map = getMessageMetadataAsDictionary(txn, g);
 			txn.setComplete();
@@ -201,7 +201,7 @@ class ClientHelperImpl implements ClientHelper {
 	@Override
 	public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
 			throws DbException, FormatException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			mergeGroupMetadata(txn, g, metadata);
 			txn.setComplete();
@@ -219,7 +219,7 @@ class ClientHelperImpl implements ClientHelper {
 	@Override
 	public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
 			throws DbException, FormatException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			mergeMessageMetadata(txn, m, metadata);
 			txn.setComplete();
diff --git a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
index df75b73e1a17fbce161b1c527086dd2808233710..7ff709b70c9062f79d9cb29c72979a405daadae0 100644
--- a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
+++ b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
@@ -51,7 +51,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook {
 			long timestamp, boolean alice, boolean active)
 			throws DbException {
 		ContactId c;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			c = db.addContact(txn, remote, local, active);
 			keyManager.addContact(txn, c, master, timestamp, alice);
@@ -68,7 +68,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook {
 	@Override
 	public Contact getContact(ContactId c) throws DbException {
 		Contact contact;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			contact = db.getContact(txn, c);
 			txn.setComplete();
@@ -81,7 +81,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook {
 	@Override
 	public Collection<Contact> getActiveContacts() throws DbException {
 		Collection<Contact> contacts;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			contacts = db.getContacts(txn);
 			txn.setComplete();
@@ -95,7 +95,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook {
 
 	@Override
 	public void removeContact(ContactId c) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			removeContact(txn, c);
 			txn.setComplete();
@@ -107,7 +107,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook {
 	@Override
 	public void setContactActive(ContactId c, boolean active)
 			throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			db.setContactActive(txn, c, active);
 			txn.setComplete();
diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
index 2178bf50ccc967769b7db57df338ede2ef7abba9..d00159903596c83da6d3750dc115571dcab6215e 100644
--- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
+++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
@@ -59,6 +59,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
@@ -78,6 +80,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 	private final EventBus eventBus;
 	private final ShutdownManager shutdown;
 	private final AtomicBoolean closed = new AtomicBoolean(false);
+	private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
 
 	private volatile int shutdownHandle = -1;
 
@@ -115,18 +118,33 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 		db.close();
 	}
 
-	public Transaction startTransaction() throws DbException {
-		return new Transaction(db.startTransaction());
+	public Transaction startTransaction(boolean readOnly) throws DbException {
+		if (readOnly) lock.readLock().lock();
+		else lock.writeLock().lock();
+		try {
+			return new Transaction(db.startTransaction(), readOnly);
+		} catch (DbException e) {
+			if (readOnly) lock.readLock().unlock();
+			else lock.writeLock().unlock();
+			throw e;
+		} catch (RuntimeException e) {
+			if (readOnly) lock.readLock().unlock();
+			else lock.writeLock().unlock();
+			throw e;
+		}
 	}
 
 	public void endTransaction(Transaction transaction) throws DbException {
-		T txn = txnClass.cast(transaction.unbox());
-		if (transaction.isComplete()) {
-			db.commitTransaction(txn);
-			for (Event e : transaction.getEvents()) eventBus.broadcast(e);
-		} else {
-			db.abortTransaction(txn);
+		try {
+			T txn = txnClass.cast(transaction.unbox());
+			if (transaction.isComplete()) db.commitTransaction(txn);
+			else db.abortTransaction(txn);
+		} finally {
+			if (transaction.isReadOnly()) lock.readLock().unlock();
+			else lock.writeLock().unlock();
 		}
+		if (transaction.isComplete())
+			for (Event e : transaction.getEvents()) eventBus.broadcast(e);
 	}
 
 	private T unbox(Transaction transaction) {
@@ -136,6 +154,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public ContactId addContact(Transaction transaction, Author remote,
 			AuthorId local, boolean active) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsLocalAuthor(txn, local))
 			throw new NoSuchLocalAuthorException();
@@ -148,6 +167,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 	}
 
 	public void addGroup(Transaction transaction, Group g) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsGroup(txn, g.getId())) {
 			db.addGroup(txn, g);
@@ -157,6 +177,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void addLocalAuthor(Transaction transaction, LocalAuthor a)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsLocalAuthor(txn, a.getId())) {
 			db.addLocalAuthor(txn, a);
@@ -166,6 +187,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void addLocalMessage(Transaction transaction, Message m, ClientId c,
 			Metadata meta, boolean shared) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsGroup(txn, m.getGroupId()))
 			throw new NoSuchGroupException();
@@ -189,6 +211,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void addTransport(Transaction transaction, TransportId t,
 			int maxLatency) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsTransport(txn, t))
 			db.addTransport(txn, t, maxLatency);
@@ -196,6 +219,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void addTransportKeys(Transaction transaction, ContactId c,
 			TransportKeys k) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -206,6 +230,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void deleteMessage(Transaction transaction, MessageId m)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsMessage(txn, m))
 			throw new NoSuchMessageException();
@@ -214,6 +239,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void deleteMessageMetadata(Transaction transaction, MessageId m)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsMessage(txn, m))
 			throw new NoSuchMessageException();
@@ -222,6 +248,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public Ack generateAck(Transaction transaction, ContactId c,
 			int maxMessages) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -233,6 +260,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public Collection<byte[]> generateBatch(Transaction transaction,
 			ContactId c, int maxLength, int maxLatency) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -250,6 +278,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public Offer generateOffer(Transaction transaction, ContactId c,
 			int maxMessages, int maxLatency) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -261,6 +290,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public Request generateRequest(Transaction transaction, ContactId c,
 			int maxMessages) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -273,6 +303,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public Collection<byte[]> generateRequestedBatch(Transaction transaction,
 			ContactId c, int maxLength, int maxLatency) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -418,6 +449,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void incrementStreamCounter(Transaction transaction, ContactId c,
 			TransportId t, long rotationPeriod) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -438,6 +470,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void mergeGroupMetadata(Transaction transaction, GroupId g,
 			Metadata meta) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsGroup(txn, g))
 			throw new NoSuchGroupException();
@@ -446,6 +479,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void mergeMessageMetadata(Transaction transaction, MessageId m,
 			Metadata meta) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsMessage(txn, m))
 			throw new NoSuchMessageException();
@@ -454,6 +488,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void mergeSettings(Transaction transaction, Settings s,
 			String namespace) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		Settings old = db.getSettings(txn, namespace);
 		Settings merged = new Settings();
@@ -467,6 +502,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void receiveAck(Transaction transaction, ContactId c, Ack a)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -482,6 +518,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void receiveMessage(Transaction transaction, ContactId c, Message m)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -497,6 +534,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void receiveOffer(Transaction transaction, ContactId c, Offer o)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -519,6 +557,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void receiveRequest(Transaction transaction, ContactId c, Request r)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -535,6 +574,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void removeContact(Transaction transaction, ContactId c)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -544,6 +584,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void removeGroup(Transaction transaction, Group g)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		GroupId id = g.getId();
 		if (!db.containsGroup(txn, id))
@@ -556,6 +597,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void removeLocalAuthor(Transaction transaction, AuthorId a)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsLocalAuthor(txn, a))
 			throw new NoSuchLocalAuthorException();
@@ -565,6 +607,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void removeTransport(Transaction transaction, TransportId t)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsTransport(txn, t))
 			throw new NoSuchTransportException();
@@ -573,6 +616,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void setContactActive(Transaction transaction, ContactId c,
 			boolean active) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -582,6 +626,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void setMessageShared(Transaction transaction, Message m,
 			boolean shared) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsMessage(txn, m.getId()))
 			throw new NoSuchMessageException();
@@ -591,6 +636,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void setMessageValid(Transaction transaction, Message m, ClientId c,
 			boolean valid) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsMessage(txn, m.getId()))
 			throw new NoSuchMessageException();
@@ -601,6 +647,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 	public void setReorderingWindow(Transaction transaction, ContactId c,
 			TransportId t, long rotationPeriod, long base, byte[] bitmap)
 			throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -611,6 +658,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void setVisibleToContact(Transaction transaction, ContactId c,
 			GroupId g, boolean visible) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		if (!db.containsContact(txn, c))
 			throw new NoSuchContactException();
@@ -636,6 +684,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 
 	public void updateTransportKeys(Transaction transaction,
 			Map<ContactId, TransportKeys> keys) throws DbException {
+		if (transaction.isReadOnly()) throw new IllegalArgumentException();
 		T txn = unbox(transaction);
 		Map<ContactId, TransportKeys> filtered =
 				new HashMap<ContactId, TransportKeys>();
diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
index d2b2d872e8ebd38954e273ae2a8579438638ba72..8d319ca4ad11a4ef6e66ebc431367829a4c3795d 100644
--- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
@@ -83,7 +83,7 @@ class ForumManagerImpl implements ForumManager {
 	public Forum getForum(GroupId g) throws DbException {
 		try {
 			Group group;
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				group = db.getGroup(txn, g);
 				txn.setComplete();
@@ -100,7 +100,7 @@ class ForumManagerImpl implements ForumManager {
 	public Collection<Forum> getForums() throws DbException {
 		try {
 			Collection<Group> groups;
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				groups = db.getGroups(txn, CLIENT_ID);
 				txn.setComplete();
@@ -132,7 +132,7 @@ class ForumManagerImpl implements ForumManager {
 		Set<AuthorId> localAuthorIds = new HashSet<AuthorId>();
 		Set<AuthorId> contactAuthorIds = new HashSet<AuthorId>();
 		Map<MessageId, BdfDictionary> metadata;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			// Load the IDs of the user's identities
 			for (LocalAuthor a : db.getLocalAuthors(txn))
diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
index b0e8fd486f810180ea15631ba8d2eb57135db72b..c30834e8f6b0a570644533b7bbd0e3b47b5a8fda 100644
--- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
@@ -131,7 +131,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 
 	@Override
 	public void addForum(Forum f) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			db.addGroup(txn, f.getGroup());
 			txn.setComplete();
@@ -144,7 +144,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	public void removeForum(Forum f) throws DbException {
 		try {
 			// Update the list shared with each contact
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				for (Contact c : db.getContacts(txn))
 					removeFromList(txn, getContactGroup(c).getId(), f);
@@ -162,7 +162,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	public Collection<Forum> getAvailableForums() throws DbException {
 		try {
 			Set<Forum> available = new HashSet<Forum>();
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				// Get any forums we subscribe to
 				Set<Group> subscribed = new HashSet<Group>(db.getGroups(txn,
@@ -196,7 +196,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	public Collection<Contact> getSharedBy(GroupId g) throws DbException {
 		try {
 			List<Contact> subscribers = new ArrayList<Contact>();
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				for (Contact c : db.getContacts(txn)) {
 					if (listContains(txn, getContactGroup(c).getId(), g, false))
@@ -216,7 +216,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	public Collection<ContactId> getSharedWith(GroupId g) throws DbException {
 		try {
 			List<ContactId> shared = new ArrayList<ContactId>();
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				for (Contact c : db.getContacts(txn)) {
 					if (listContains(txn, getContactGroup(c).getId(), g, true))
@@ -236,7 +236,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	public void setSharedWith(GroupId g, Collection<ContactId> shared)
 			throws DbException {
 		try {
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				// Retrieve the forum
 				Forum f = parseForum(db.getGroup(txn, g));
@@ -268,7 +268,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 	@Override
 	public void setSharedWithAll(GroupId g) throws DbException {
 		try {
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				// Retrieve the forum
 				Forum f = parseForum(db.getGroup(txn, g));
diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
index 997456d2941dad65c40509e8507dc0eb9a5ca06e..b3d7a1f4d8213f8427963457ff8a3d80b8c91a0f 100644
--- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
+++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
@@ -37,7 +37,7 @@ class IdentityManagerImpl implements IdentityManager {
 
 	@Override
 	public void addLocalAuthor(LocalAuthor localAuthor) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			db.addLocalAuthor(txn, localAuthor);
 			for (AddIdentityHook hook : addHooks)
@@ -51,7 +51,7 @@ class IdentityManagerImpl implements IdentityManager {
 	@Override
 	public LocalAuthor getLocalAuthor(AuthorId a) throws DbException {
 		LocalAuthor author;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			author = db.getLocalAuthor(txn, a);
 			txn.setComplete();
@@ -64,7 +64,7 @@ class IdentityManagerImpl implements IdentityManager {
 	@Override
 	public Collection<LocalAuthor> getLocalAuthors() throws DbException {
 		Collection<LocalAuthor> authors;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			authors = db.getLocalAuthors(txn);
 			txn.setComplete();
@@ -76,7 +76,7 @@ class IdentityManagerImpl implements IdentityManager {
 
 	@Override
 	public void removeLocalAuthor(AuthorId a) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			LocalAuthor localAuthor = db.getLocalAuthor(txn, a);
 			for (RemoveIdentityHook hook : removeHooks)
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index c1a0eb797cad84b3130b76785e1d397bb682dc32..e7e64552f5c3a6d42f6b8ec2123c2edf03ebfe1b 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -106,7 +106,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
 	@Override
 	public GroupId getConversationId(ContactId c) throws DbException {
 		Contact contact;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			contact = db.getContact(txn, c);
 			txn.setComplete();
@@ -121,7 +121,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
 			throws DbException {
 		Map<MessageId, BdfDictionary> metadata;
 		Collection<MessageStatus> statuses;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			GroupId g = getContactGroup(db.getContact(txn, c)).getId();
 			metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
index 2c90166526ae97810aca79d0e1d8d6cddb1e4e1e..9910ff42fe9facb2d1a0a5eebebff2cc89b1f6da 100644
--- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
+++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
@@ -84,7 +84,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 	@Override
 	public void addRemoteProperties(ContactId c, DeviceId dev,
 			Map<TransportId, TransportProperties> props) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			Group g = getContactGroup(db.getContact(txn, c));
 			for (Entry<TransportId, TransportProperties> e : props.entrySet()) {
@@ -101,7 +101,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 	public Map<TransportId, TransportProperties> getLocalProperties()
 			throws DbException {
 		Map<TransportId, TransportProperties> local;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			local = getLocalProperties(txn);
 			txn.setComplete();
@@ -116,7 +116,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 			throws DbException {
 		try {
 			TransportProperties p = null;
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				// Find the latest local update
 				LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
@@ -146,7 +146,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 		try {
 			Map<ContactId, TransportProperties> remote =
 					new HashMap<ContactId, TransportProperties>();
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(true);
 			try {
 				for (Contact c : db.getContacts(txn)) {
 					Group g = getContactGroup(c);
@@ -173,7 +173,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 	public void mergeLocalProperties(TransportId t, TransportProperties p)
 			throws DbException {
 		try {
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				// Create the local group if necessary
 				db.addGroup(txn, localGroup);
diff --git a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
index 4ff0ff2217cd9c0ec5a5e16bba6e2f121e9fca25..3df277318cb41650fc69ff5af2f15ee80e44cb2d 100644
--- a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
+++ b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
@@ -21,7 +21,7 @@ class SettingsManagerImpl implements SettingsManager {
 	@Override
 	public Settings getSettings(String namespace) throws DbException {
 		Settings s;
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(true);
 		try {
 			s = db.getSettings(txn, namespace);
 			txn.setComplete();
@@ -33,7 +33,7 @@ class SettingsManagerImpl implements SettingsManager {
 
 	@Override
 	public void mergeSettings(Settings s, String namespace) throws DbException {
-		Transaction txn = db.startTransaction();
+		Transaction txn = db.startTransaction(false);
 		try {
 			db.mergeSettings(txn, s, namespace);
 			txn.setComplete();
diff --git a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
index f9a6726d54ad0d428944c21eb63acddb8cbb5ecf..7c87c3151419ed36f9d7a0d95bc93d9663a79479 100644
--- a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
+++ b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
@@ -172,7 +172,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Ack a;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
 					txn.setComplete();
@@ -213,7 +213,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Collection<byte[]> b;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					b = db.generateRequestedBatch(txn, contactId,
 							MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
@@ -255,7 +255,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Offer o;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS,
 							maxLatency);
@@ -297,7 +297,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Request r;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS);
 					txn.setComplete();
diff --git a/briar-core/src/org/briarproject/sync/IncomingSession.java b/briar-core/src/org/briarproject/sync/IncomingSession.java
index 970afbf8b084d009fa8083df988ef5cff4a7485d..2a06d29cb0e18a70aa4a230b68223b0fb5b984e9 100644
--- a/briar-core/src/org/briarproject/sync/IncomingSession.java
+++ b/briar-core/src/org/briarproject/sync/IncomingSession.java
@@ -99,7 +99,7 @@ class IncomingSession implements SyncSession, EventListener {
 
 		public void run() {
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					db.receiveAck(txn, contactId, ack);
 					txn.setComplete();
@@ -123,7 +123,7 @@ class IncomingSession implements SyncSession, EventListener {
 
 		public void run() {
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					db.receiveMessage(txn, contactId, message);
 					txn.setComplete();
@@ -147,7 +147,7 @@ class IncomingSession implements SyncSession, EventListener {
 
 		public void run() {
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					db.receiveOffer(txn, contactId, offer);
 					txn.setComplete();
@@ -171,7 +171,7 @@ class IncomingSession implements SyncSession, EventListener {
 
 		public void run() {
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					db.receiveRequest(txn, contactId, request);
 					txn.setComplete();
diff --git a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
index d69b8eb81eea73edb33e030cadd602ddf37d4454..5623c275e70d923e6be402fb3337c4dd7e2cc120 100644
--- a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
+++ b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
@@ -114,7 +114,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Ack a;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
 					txn.setComplete();
@@ -156,7 +156,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
 			if (interrupted) return;
 			try {
 				Collection<byte[]> b;
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					b = db.generateBatch(txn, contactId,
 							MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
diff --git a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
index 4837a1b57a813175fefbd9a24b559d1ab3616efb..89c35459af995d1758670f8747de534a4a21373b 100644
--- a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
+++ b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
@@ -83,7 +83,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 			public void run() {
 				try {
 					Queue<MessageId> unvalidated = new LinkedList<MessageId>();
-					Transaction txn = db.startTransaction();
+					Transaction txn = db.startTransaction(true);
 					try {
 						unvalidated.addAll(db.getMessagesToValidate(txn, c));
 						txn.setComplete();
@@ -106,7 +106,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 				try {
 					Message m = null;
 					Group g = null;
-					Transaction txn = db.startTransaction();
+					Transaction txn = db.startTransaction(true);
 					try {
 						MessageId id = unvalidated.poll();
 						byte[] raw = db.getRawMessage(txn, id);
@@ -160,7 +160,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 		dbExecutor.execute(new Runnable() {
 			public void run() {
 				try {
-					Transaction txn = db.startTransaction();
+					Transaction txn = db.startTransaction(false);
 					try {
 						if (meta == null) {
 							db.setMessageValid(txn, m, c, false);
@@ -198,7 +198,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 			public void run() {
 				try {
 					Group g;
-					Transaction txn = db.startTransaction();
+					Transaction txn = db.startTransaction(true);
 					try {
 						g = db.getGroup(txn, m.getGroupId());
 						txn.setComplete();
diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
index 276daf453a91c8e8bb616a8f15391cde6d0e96cc..6b3093a45f8b721f8de4c69613c1717b3585245a 100644
--- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
+++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
@@ -73,7 +73,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
 			latencies.put(f.getId(), f.getMaxLatency());
 		try {
 			Collection<Contact> contacts;
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				contacts = db.getContacts(txn);
 				for (Entry<TransportId, Integer> e : latencies.entrySet())
@@ -123,7 +123,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
 		// Activate the contact if not already active
 		if (!activeContacts.containsKey(ctx.getContactId())) {
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(false);
 				try {
 					db.setContactActive(txn, ctx.getContactId(), true);
 					txn.setComplete();
diff --git a/briar-core/src/org/briarproject/transport/TransportKeyManager.java b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
index b8bcdfb3f99693971e0a5c37e2c991f9091d3111..8b1ee0a5857a2a57fd812219fb9fd3aaca021fbc 100644
--- a/briar-core/src/org/briarproject/transport/TransportKeyManager.java
+++ b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
@@ -67,7 +67,7 @@ class TransportKeyManager {
 			// Load the transport keys from the DB
 			Map<ContactId, TransportKeys> loaded;
 			try {
-				Transaction txn = db.startTransaction();
+				Transaction txn = db.startTransaction(true);
 				try {
 					loaded = db.getTransportKeys(txn, transportId);
 					txn.setComplete();
@@ -129,7 +129,7 @@ class TransportKeyManager {
 	private void updateTransportKeys(Map<ContactId, TransportKeys> rotated)
 		throws DbException {
 		if (!rotated.isEmpty()) {
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				db.updateTransportKeys(txn, rotated);
 				txn.setComplete();
@@ -198,7 +198,7 @@ class TransportKeyManager {
 					outKeys.getStreamCounter());
 			// Increment the stream counter and write it back to the DB
 			outKeys.incrementStreamCounter();
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				db.incrementStreamCounter(txn, c, transportId,
 						outKeys.getRotationPeriod());
@@ -244,7 +244,7 @@ class TransportKeyManager {
 				inContexts.remove(new Bytes(removeTag));
 			}
 			// Write the window back to the DB
-			Transaction txn = db.startTransaction();
+			Transaction txn = db.startTransaction(false);
 			try {
 				db.setReorderingWindow(txn, tagCtx.contactId, transportId,
 						inKeys.getRotationPeriod(), window.getBase(),
diff --git a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
index 3cbed06cb9c4ab6835d62355ca739d1cf54bfdff..cf816fd88e4614430de2bc34a99a56a08b6918b0 100644
--- a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
@@ -56,7 +56,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase {
 				context.mock(QueueMessageFactory.class);
 		final ValidationManager validationManager =
 				context.mock(ValidationManager.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		final byte[] body = new byte[123];
 		final Metadata groupMetadata = new Metadata();
 		final Metadata messageMetadata = new Metadata();
@@ -249,7 +249,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase {
 				new AtomicReference<IncomingMessageHook>();
 		final IncomingQueueMessageHook incomingQueueMessageHook =
 				context.mock(IncomingQueueMessageHook.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		final Metadata groupMetadata = new Metadata();
 		final byte[] queueState = new byte[123];
 		groupMetadata.put(QUEUE_STATE_KEY, queueState);
@@ -300,7 +300,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase {
 				new AtomicReference<IncomingMessageHook>();
 		final IncomingQueueMessageHook incomingQueueMessageHook =
 				context.mock(IncomingQueueMessageHook.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		final Metadata groupMetadata = new Metadata();
 		final byte[] queueState = new byte[123];
 		groupMetadata.put(QUEUE_STATE_KEY, queueState);
@@ -355,7 +355,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase {
 				new AtomicReference<IncomingMessageHook>();
 		final IncomingQueueMessageHook incomingQueueMessageHook =
 				context.mock(IncomingQueueMessageHook.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		final Metadata groupMetadata = new Metadata();
 		final byte[] queueState = new byte[123];
 		groupMetadata.put(QUEUE_STATE_KEY, queueState);
@@ -412,7 +412,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase {
 				new AtomicReference<IncomingMessageHook>();
 		final IncomingQueueMessageHook incomingQueueMessageHook =
 				context.mock(IncomingQueueMessageHook.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		final Metadata groupMetadata = new Metadata();
 		final byte[] queueState = new byte[123];
 		groupMetadata.put(QUEUE_STATE_KEY, queueState);
diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
index 4049a4091db098696bf672b5b4a6fdffbb343f79..02531d08d1165f34c1aaeea85ece32a9fd43cbeb 100644
--- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
+++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
@@ -192,7 +192,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 				shutdown);
 
 		assertFalse(db.open());
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addLocalAuthor(transaction, localAuthor);
 			assertEquals(contactId,
@@ -233,7 +233,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addLocalMessage(transaction, message, clientId, metadata, true);
 			fail();
@@ -276,7 +276,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addLocalMessage(transaction, message, clientId, metadata, true);
 			transaction.setComplete();
@@ -306,7 +306,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addTransportKeys(transaction, contactId, createTransportKeys());
 			fail();
@@ -316,7 +316,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.generateAck(transaction, contactId, 123);
 			fail();
@@ -326,7 +326,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.generateBatch(transaction, contactId, 123, 456);
 			fail();
@@ -336,7 +336,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.generateOffer(transaction, contactId, 123, 456);
 			fail();
@@ -346,7 +346,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.generateRequest(transaction, contactId, 123);
 			fail();
@@ -356,7 +356,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getContact(transaction, contactId);
 			fail();
@@ -366,7 +366,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getMessageStatus(transaction, contactId, groupId);
 			fail();
@@ -376,7 +376,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getMessageStatus(transaction, contactId, messageId);
 			fail();
@@ -386,7 +386,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.incrementStreamCounter(transaction, contactId, transportId, 0);
 			fail();
@@ -396,7 +396,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.isVisibleToContact(transaction, contactId, groupId);
 			fail();
@@ -406,7 +406,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			Ack a = new Ack(Collections.singletonList(messageId));
 			db.receiveAck(transaction, contactId, a);
@@ -417,7 +417,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.receiveMessage(transaction, contactId, message);
 			fail();
@@ -427,7 +427,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			Offer o = new Offer(Collections.singletonList(messageId));
 			db.receiveOffer(transaction, contactId, o);
@@ -438,7 +438,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			Request r = new Request(Collections.singletonList(messageId));
 			db.receiveRequest(transaction, contactId, r);
@@ -449,7 +449,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.removeContact(transaction, contactId);
 			fail();
@@ -459,7 +459,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setContactActive(transaction, contactId, true);
 			fail();
@@ -469,7 +469,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setReorderingWindow(transaction, contactId, transportId, 0, 0,
 					new byte[REORDERING_WINDOW_SIZE / 8]);
@@ -480,7 +480,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setVisibleToContact(transaction, contactId, groupId, true);
 			fail();
@@ -512,7 +512,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addContact(transaction, author, localAuthorId, true);
 			fail();
@@ -522,7 +522,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getLocalAuthor(transaction, localAuthorId);
 			fail();
@@ -532,7 +532,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.removeLocalAuthor(transaction, localAuthorId);
 			fail();
@@ -568,7 +568,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.getGroup(transaction, groupId);
 			fail();
@@ -578,7 +578,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getGroupMetadata(transaction, groupId);
 			fail();
@@ -588,7 +588,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getMessageStatus(transaction, contactId, groupId);
 			fail();
@@ -598,7 +598,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.isVisibleToContact(transaction, contactId, groupId);
 			fail();
@@ -608,7 +608,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.mergeGroupMetadata(transaction, groupId, metadata);
 			fail();
@@ -618,7 +618,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.removeGroup(transaction, group);
 			fail();
@@ -628,7 +628,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setVisibleToContact(transaction, contactId, groupId, true);
 			fail();
@@ -663,7 +663,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.deleteMessage(transaction, messageId);
 			fail();
@@ -673,7 +673,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.deleteMessageMetadata(transaction, messageId);
 			fail();
@@ -683,7 +683,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getRawMessage(transaction, messageId);
 			fail();
@@ -693,7 +693,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getMessageMetadata(transaction, messageId);
 			fail();
@@ -703,7 +703,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getMessageStatus(transaction, contactId, messageId);
 			fail();
@@ -713,7 +713,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.mergeMessageMetadata(transaction, messageId, metadata);
 			fail();
@@ -723,7 +723,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setMessageShared(transaction, message, true);
 			fail();
@@ -733,7 +733,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setMessageValid(transaction, message, clientId, true);
 			fail();
@@ -787,7 +787,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.addLocalAuthor(transaction, localAuthor);
 			assertEquals(contactId,
@@ -797,7 +797,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.getTransportKeys(transaction, transportId);
 			fail();
@@ -807,7 +807,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.incrementStreamCounter(transaction, contactId, transportId, 0);
 			fail();
@@ -817,7 +817,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.removeTransport(transaction, transportId);
 			fail();
@@ -827,7 +827,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction();
+		transaction = db.startTransaction(false);
 		try {
 			db.setReorderingWindow(transaction, contactId, transportId, 0, 0,
 					new byte[REORDERING_WINDOW_SIZE / 8]);
@@ -863,7 +863,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Ack a = db.generateAck(transaction, contactId, 123);
 			assertEquals(messagesToAck, a.getMessageIds());
@@ -907,7 +907,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			assertEquals(messages, db.generateBatch(transaction, contactId,
 					size * 2, maxLatency));
@@ -944,7 +944,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
 			assertEquals(ids, o.getMessageIds());
@@ -978,7 +978,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Request r = db.generateRequest(transaction, contactId, 123);
 			assertEquals(ids, r.getMessageIds());
@@ -1023,7 +1023,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			assertEquals(messages, db.generateRequestedBatch(transaction,
 					contactId, size * 2, maxLatency));
@@ -1056,7 +1056,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Ack a = new Ack(Collections.singletonList(messageId));
 			db.receiveAck(transaction, contactId, a);
@@ -1099,7 +1099,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.receiveMessage(transaction, contactId, message);
 			transaction.setComplete();
@@ -1135,7 +1135,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.receiveMessage(transaction, contactId, message);
 			transaction.setComplete();
@@ -1165,7 +1165,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.receiveMessage(transaction, contactId, message);
 			transaction.setComplete();
@@ -1217,7 +1217,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Offer o = new Offer(Arrays.asList(messageId, messageId1,
 					messageId2, messageId3));
@@ -1252,7 +1252,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			Request r = new Request(Collections.singletonList(messageId));
 			db.receiveRequest(transaction, contactId, r);
@@ -1293,7 +1293,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.setVisibleToContact(transaction, contactId, groupId, true);
 			transaction.setComplete();
@@ -1326,7 +1326,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.setVisibleToContact(transaction, contactId, groupId, true);
 			transaction.setComplete();
@@ -1368,7 +1368,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			db.updateTransportKeys(transaction, keys);
 			assertEquals(keys, db.getTransportKeys(transaction, transportId));
@@ -1434,7 +1434,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 		DatabaseComponent db = createDatabaseComponent(database, eventBus,
 				shutdown);
 
-		Transaction transaction = db.startTransaction();
+		Transaction transaction = db.startTransaction(false);
 		try {
 			// First merge should broadcast an event
 			db.mergeSettings(transaction, update, "namespace");
diff --git a/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java b/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java
index c71df9982e3109cca195bcc508a31f543ae0e101..57e6eb2fe54c29f6184506ae34cd03249c4df35f 100644
--- a/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java
+++ b/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java
@@ -46,20 +46,20 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
 	public void testNothingToSend() throws Exception {
 		final SimplexOutgoingSession session = new SimplexOutgoingSession(db,
 				dbExecutor, eventBus, contactId, maxLatency, packetWriter);
-		final Transaction noAckTxn = new Transaction(null);
-		final Transaction noMsgTxn = new Transaction(null);
+		final Transaction noAckTxn = new Transaction(null, false);
+		final Transaction noMsgTxn = new Transaction(null, false);
 
 		context.checking(new Expectations() {{
 			// Add listener
 			oneOf(eventBus).addListener(session);
 			// No acks to send
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(noAckTxn));
 			oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
 			will(returnValue(null));
 			oneOf(db).endTransaction(noAckTxn);
 			// No messages to send
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(noMsgTxn));
 			oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
 					with(any(int.class)), with(maxLatency));
@@ -82,23 +82,23 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
 		final byte[] raw = new byte[1234];
 		final SimplexOutgoingSession session = new SimplexOutgoingSession(db,
 				dbExecutor, eventBus, contactId, maxLatency, packetWriter);
-		final Transaction ackTxn = new Transaction(null);
-		final Transaction noAckTxn = new Transaction(null);
-		final Transaction msgTxn = new Transaction(null);
-		final Transaction noMsgTxn = new Transaction(null);
+		final Transaction ackTxn = new Transaction(null, false);
+		final Transaction noAckTxn = new Transaction(null, false);
+		final Transaction msgTxn = new Transaction(null, false);
+		final Transaction noMsgTxn = new Transaction(null, false);
 
 		context.checking(new Expectations() {{
 			// Add listener
 			oneOf(eventBus).addListener(session);
 			// One ack to send
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(ackTxn));
 			oneOf(db).generateAck(ackTxn, contactId, MAX_MESSAGE_IDS);
 			will(returnValue(ack));
 			oneOf(db).endTransaction(ackTxn);
 			oneOf(packetWriter).writeAck(ack);
 			// One message to send
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(msgTxn));
 			oneOf(db).generateBatch(with(msgTxn), with(contactId),
 					with(any(int.class)), with(maxLatency));
@@ -106,13 +106,13 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
 			oneOf(db).endTransaction(msgTxn);
 			oneOf(packetWriter).writeMessage(raw);
 			// No more acks
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(noAckTxn));
 			oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
 			will(returnValue(null));
 			oneOf(db).endTransaction(noAckTxn);
 			// No more messages
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(noMsgTxn));
 			oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
 					with(any(int.class)), with(maxLatency));
diff --git a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
index d883a1ef20f746256b698972bd0a450cbf837ca3..561bb26ce4d6f6cfcdc8fc29eb37bc2240dd544a 100644
--- a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
@@ -58,20 +58,20 @@ public class ValidationManagerImplTest extends BriarTestCase {
 		final MessageValidator validator = context.mock(MessageValidator.class);
 		final IncomingMessageHook hook =
 				context.mock(IncomingMessageHook.class);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
-		final Transaction txn2 = new Transaction(null);
-		final Transaction txn3 = new Transaction(null);
-		final Transaction txn4 = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
+		final Transaction txn1 = new Transaction(null, false);
+		final Transaction txn2 = new Transaction(null, false);
+		final Transaction txn3 = new Transaction(null, false);
+		final Transaction txn4 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Get messages to validate
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getMessagesToValidate(txn, clientId);
 			will(returnValue(Arrays.asList(messageId, messageId1)));
 			oneOf(db).endTransaction(txn);
 			// Load the first raw message and group
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
 			oneOf(db).getRawMessage(txn1, messageId);
 			will(returnValue(raw));
@@ -82,7 +82,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(validator).validateMessage(message, group);
 			will(returnValue(metadata));
 			// Store the validation result for the first message
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn2));
 			oneOf(db).mergeMessageMetadata(txn2, messageId, metadata);
 			oneOf(db).setMessageValid(txn2, message, clientId, true);
@@ -91,7 +91,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(hook).incomingMessage(txn2, message, metadata);
 			oneOf(db).endTransaction(txn2);
 			// Load the second raw message and group
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn3));
 			oneOf(db).getRawMessage(txn3, messageId1);
 			will(returnValue(raw));
@@ -102,7 +102,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(validator).validateMessage(message1, group);
 			will(returnValue(null));
 			// Store the validation result for the second message
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn4));
 			oneOf(db).setMessageValid(txn4, message1, clientId, false);
 			oneOf(db).endTransaction(txn4);
@@ -127,25 +127,25 @@ public class ValidationManagerImplTest extends BriarTestCase {
 		final MessageValidator validator = context.mock(MessageValidator.class);
 		final IncomingMessageHook hook =
 				context.mock(IncomingMessageHook.class);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
-		final Transaction txn2 = new Transaction(null);
-		final Transaction txn3 = new Transaction(null);
+		final Transaction txn = new Transaction(null, true);
+		final Transaction txn1 = new Transaction(null, true);
+		final Transaction txn2 = new Transaction(null, true);
+		final Transaction txn3 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Get messages to validate
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getMessagesToValidate(txn, clientId);
 			will(returnValue(Arrays.asList(messageId, messageId1)));
 			oneOf(db).endTransaction(txn);
 			// Load the first raw message - *gasp* it's gone!
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
 			oneOf(db).getRawMessage(txn1, messageId);
 			will(throwException(new NoSuchMessageException()));
 			oneOf(db).endTransaction(txn1);
 			// Load the second raw message and group
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn2));
 			oneOf(db).getRawMessage(txn2, messageId1);
 			will(returnValue(raw));
@@ -156,7 +156,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(validator).validateMessage(message1, group);
 			will(returnValue(null));
 			// Store the validation result for the second message
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn3));
 			oneOf(db).setMessageValid(txn3, message1, clientId, false);
 			oneOf(db).endTransaction(txn3);
@@ -181,19 +181,19 @@ public class ValidationManagerImplTest extends BriarTestCase {
 		final MessageValidator validator = context.mock(MessageValidator.class);
 		final IncomingMessageHook hook =
 				context.mock(IncomingMessageHook.class);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
-		final Transaction txn2 = new Transaction(null);
-		final Transaction txn3 = new Transaction(null);
+		final Transaction txn = new Transaction(null, true);
+		final Transaction txn1 = new Transaction(null, true);
+		final Transaction txn2 = new Transaction(null, true);
+		final Transaction txn3 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Get messages to validate
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getMessagesToValidate(txn, clientId);
 			will(returnValue(Arrays.asList(messageId, messageId1)));
 			oneOf(db).endTransaction(txn);
 			// Load the first raw message
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
 			oneOf(db).getRawMessage(txn1, messageId);
 			will(returnValue(raw));
@@ -202,7 +202,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			will(throwException(new NoSuchGroupException()));
 			oneOf(db).endTransaction(txn1);
 			// Load the second raw message and group
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn2));
 			oneOf(db).getRawMessage(txn2, messageId1);
 			will(returnValue(raw));
@@ -213,7 +213,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(validator).validateMessage(message1, group);
 			will(returnValue(null));
 			// Store the validation result for the second message
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn3));
 			oneOf(db).setMessageValid(txn3, message1, clientId, false);
 			oneOf(db).endTransaction(txn3);
@@ -237,11 +237,11 @@ public class ValidationManagerImplTest extends BriarTestCase {
 		final MessageValidator validator = context.mock(MessageValidator.class);
 		final IncomingMessageHook hook =
 				context.mock(IncomingMessageHook.class);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
+		final Transaction txn = new Transaction(null, true);
+		final Transaction txn1 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Load the group
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getGroup(txn, groupId);
 			will(returnValue(group));
@@ -250,7 +250,7 @@ public class ValidationManagerImplTest extends BriarTestCase {
 			oneOf(validator).validateMessage(message, group);
 			will(returnValue(metadata));
 			// Store the validation result
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn1));
 			oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
 			oneOf(db).setMessageValid(txn1, message, clientId, true);
diff --git a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java
index 148262b27557af93fd8a541db9d881002d8a5e46..5b674dbdb59f540d12b28cd5c82dbbc710b82691 100644
--- a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java
+++ b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java
@@ -57,7 +57,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		final CryptoComponent crypto = context.mock(CryptoComponent.class);
 		final Timer timer = context.mock(Timer.class);
 		final Clock clock = context.mock(Clock.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, true);
 		final Map<ContactId, TransportKeys> loaded =
 				new LinkedHashMap<ContactId, TransportKeys>();
 		final TransportKeys shouldRotate = createTransportKeys(900, 0);
@@ -65,13 +65,13 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		loaded.put(contactId, shouldRotate);
 		loaded.put(contactId1, shouldNotRotate);
 		final TransportKeys rotated = createTransportKeys(1000, 0);
-		final Transaction txn1 = new Transaction(null);
+		final Transaction txn1 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Get the current time (1 ms after start of rotation period 1000)
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(rotationPeriodLength * 1000 + 1));
 			// Load the transport keys
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getTransportKeys(txn, transportId);
 			will(returnValue(loaded));
@@ -88,7 +88,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 				will(new EncodeTagAction());
 			}
 			// Save the keys that were rotated
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn1));
 			oneOf(db).updateTransportKeys(txn1,
 					Collections.singletonMap(contactId, rotated));
@@ -115,7 +115,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		final boolean alice = true;
 		final TransportKeys transportKeys = createTransportKeys(999, 0);
 		final TransportKeys rotated = createTransportKeys(1000, 0);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			oneOf(crypto).deriveTransportKeys(transportId, masterKey, 999,
 					alice);
@@ -174,7 +174,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		// The stream counter has been exhausted
 		final TransportKeys transportKeys = createTransportKeys(1000,
 				MAX_32_BIT_UNSIGNED + 1);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000,
 					alice);
@@ -217,8 +217,8 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		// The stream counter can be used one more time before being exhausted
 		final TransportKeys transportKeys = createTransportKeys(1000,
 				MAX_32_BIT_UNSIGNED);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
+		final Transaction txn1 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000,
 					alice);
@@ -238,7 +238,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 			// Save the keys
 			oneOf(db).addTransportKeys(txn, contactId, transportKeys);
 			// Increment the stream counter
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn1));
 			oneOf(db).incrementStreamCounter(txn1, contactId, transportId,
 					1000);
@@ -275,7 +275,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		final Clock clock = context.mock(Clock.class);
 		final boolean alice = true;
 		final TransportKeys transportKeys = createTransportKeys(1000, 0);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000,
 					alice);
@@ -316,8 +316,8 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		final Clock clock = context.mock(Clock.class);
 		final boolean alice = true;
 		final TransportKeys transportKeys = createTransportKeys(1000, 0);
-		final Transaction txn = new Transaction(null);
-		final Transaction txn1 = new Transaction(null);
+		final Transaction txn = new Transaction(null, false);
+		final Transaction txn1 = new Transaction(null, false);
 		// Keep a copy of the tags
 		final List<byte[]> tags = new ArrayList<byte[]>();
 		context.checking(new Expectations() {{
@@ -343,7 +343,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 					with(tagKey), with((long) REORDERING_WINDOW_SIZE));
 			will(new EncodeTagAction(tags));
 			// Save the reordering window (previous rotation period, base 1)
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn1));
 			oneOf(db).setReorderingWindow(txn1, contactId, transportId, 999,
 					1, new byte[REORDERING_WINDOW_SIZE / 8]);
@@ -382,18 +382,18 @@ public class TransportKeyManagerTest extends BriarTestCase {
 		final CryptoComponent crypto = context.mock(CryptoComponent.class);
 		final Timer timer = context.mock(Timer.class);
 		final Clock clock = context.mock(Clock.class);
-		final Transaction txn = new Transaction(null);
+		final Transaction txn = new Transaction(null, true);
 		final TransportKeys transportKeys = createTransportKeys(1000, 0);
 		final Map<ContactId, TransportKeys> loaded =
 				Collections.singletonMap(contactId, transportKeys);
 		final TransportKeys rotated = createTransportKeys(1001, 0);
-		final Transaction txn1 = new Transaction(null);
+		final Transaction txn1 = new Transaction(null, false);
 		context.checking(new Expectations() {{
 			// Get the current time (the start of rotation period 1000)
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(rotationPeriodLength * 1000));
 			// Load the transport keys
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
 			oneOf(db).getTransportKeys(txn, transportId);
 			will(returnValue(loaded));
@@ -425,7 +425,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
 				will(new EncodeTagAction());
 			}
 			// Save the keys that were rotated
-			oneOf(db).startTransaction();
+			oneOf(db).startTransaction(false);
 			will(returnValue(txn1));
 			oneOf(db).updateTransportKeys(txn1,
 					Collections.singletonMap(contactId, rotated));