Realm-java: Realm is already in write transaction

Created on 2 Oct 2018  路  15Comments  路  Source: realm/realm-java

I am using below method to write in DB, but sometimes getting random issue "The Realm is already in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_SharedRealm.cpp line 263 error."

can someone pls let me know proper solution ?
Yes, we have multiple write transaction from background service and also from UI thread

private static void insertCustomerData(T obj) {
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
if (obj instanceof CustomerData) {

        realm.copyToRealmOrUpdate(obj);
        realm.commitTransaction();
    } else {

        realm.copyToRealmOrUpdate(obj);
        realm.commitTransaction();
    }
    realm.close();
}

Goal

Actual Results

Steps & Code to Reproduce



Version of Realm and tooling

Realm version(s): ?

Realm Sync feature enabled: Yes/No

Android Studio version: ?

Android Build Tools version: ? 25.0.0

Gradle version: ?

Which Android version and device(s): ? Emulator Android 8.1 Oreo

O-Community T-Help

Most helpful comment

You get the exception if you already started a write transaction somewhere on the same thread.

Note that, Realm realm = Realm.getDefaultInstance(); doesn't return a new instance if one is already open, then it will return the existing one, so a pattern like:

Realm realm1 = Realm.getDefaultInstance();
realm1.beginTransaction();
Realm realm2 = Realm.getDefaultInstance();
realm2.beginTransaction();

Will result in the error you are seeing.

All 15 comments

You get the exception if you already started a write transaction somewhere on the same thread.

Note that, Realm realm = Realm.getDefaultInstance(); doesn't return a new instance if one is already open, then it will return the existing one, so a pattern like:

Realm realm1 = Realm.getDefaultInstance();
realm1.beginTransaction();
Realm realm2 = Realm.getDefaultInstance();
realm2.beginTransaction();

Will result in the error you are seeing.

You get the exception if you already started a write transaction somewhere on the same thread.

Note that, Realm realm = Realm.getDefaultInstance(); doesn't return a new instance if one is already open, then it will return the existing one, so a pattern like:

Realm realm1 = Realm.getDefaultInstance();
realm1.beginTransaction();
Realm realm2 = Realm.getDefaultInstance();
realm2.beginTransaction();

Will result in the error you are seeing.

What's the error resolution ?Any Blog/link of SO that can help me to resolve this issue ?
@cmelchior

I've only seen this happen throughout the years if this kind of method is called inside a RealmChangeListener.

I've only seen this happen throughout the years if this kind of method is called inside a RealmChangeListener.

@Zhuinden pls discuss how can i ensure that this is really called from RealmChangeListener and whats the way to resolve this issue and avoid to call from RealmChangeListener ?

@engr-erum That would require knowledge about the entire code base and knowledge about your app architecture. I would start tracing what starts those writes, something must be triggering them.

One work-around is to wrap your code in

```
boolean commitNow = false;
if (!realm.isInTransaction()) {
realm.beginTransaction();
commitNow = true;
}

// Logic

if (commitNow) {
realm.commitTransaction();
}

````

But I would really not recommend it as it sounds like you don't know what your outer write is doing.

and whats the way to resolve this issue and avoid to call from RealmChangeListener ?

Well just... not call realm.beginTransaction() inside a RealmChangeListener :smile:

But the "hacky" way to do it is to wrap the entire transaction logic and whatever else is needed with it in a handler.post.

and whats the way to resolve this issue and avoid to call from RealmChangeListener ?

Well just... not call realm.beginTransaction() inside a RealmChangeListener 馃槃

But the "hacky" way to do it is to wrap it in a handler.post.

i read data from realm db and recieved RealmList then trying to add null in some fields and saving realmList in db.
Is this the cause of "realm is already in write transaction "

@engr-erum That would require knowledge about the entire code base and knowledge about your app architecture. I would start tracing what starts those writes, something must be triggering them.

One work-around is to wrap your code in

boolean commitNow = false;
if (!realm.isInTransaction()) {
  realm.beginTransaction();
  commitNow = true;
}

// Logic

if (commitNow) {
  realm.commitTransaction();
}

But I would really not recommend it as it sounds like you don't know what your outer write is doing.

and whats the way to resolve this issue and avoid to call from RealmChangeListener ?

Well just... not call realm.beginTransaction() inside a RealmChangeListener 馃槃

But the "hacky" way to do it is to wrap it in a handler.post.

i read data from realm db and recieved RealmList then trying to add null in some fields and saving realmList in db.
Is this the cause of "realm is already in write transaction "

Not as you describe it there, but depending on where you "read from realmdb", then yes, it could happen.

Basically, you need to analyze your call chain. Somewhere, something started a transaction and then called your method that also attempts to start a transaction (which then fails with the exception you see).

That something is on the same thread though. Realm should work perfectly well if you start write transactions on different threads (they will just block each other).

But like @Zhuinden says. Calling realm.beginTransaction() will trigger all change listeners on that thread, so if do a write inside a change listener you will end up in the situation you are in.

Not as you describe it there, but depending on where you "read from realmdb", then yes, it could happen.

Basically, you need to analyze your call chain. Somewhere, something started a transaction and then called your method that also attempts to start a transaction (which then fails with the exception you see).

That something is on the same thread though. Realm should work perfectly well if you start write transactions on different threads (they will just block each other).

But like @Zhuinden says. Calling realm.beginTransaction() will trigger all change listeners on that thread, so if do a write inside a change listener you will end up in the situation you are in.

It will be really good to share examples with some codes that can exactly resolve the issue.
Reading data , writing some objects /realm list to null and then update Realmlist back in db

I cannot show you an example on how to fix your exact issue, because it isn't at all clear how you ended up with that error. Like I mentioned before, you need to analyze your call chain to see what might trigger two calls to Realm.beginTransaction(). You can start by using Android Studios debugger. Put a breakpoint where the exception is and you can see the entire call chain down to that method.

Regarding a basic example of opening/reading/writing then this

Realm realm = Realm.getDefaultInstance();
realm.beginTransaction(); 
Person p = realm.where(Person.class).equalTo("id", 42).findFirst(); // Find object / read object
p.getChildren().clear(); // Write a change by clearing all children
realm.commitTransaction();

But clearly, that is too simplified for whatever problem you run into. I would suggest browsing our examples instead to get an idea on how to use Realm. Starting with our IntroExample: https://github.com/realm/realm-java/blob/master/examples/introExample/src/main/java/io/realm/examples/intro/IntroExampleActivity.java

```

Please use try(Realm realm = Realm.getDefaultInstance()) { in your sample for future users who mess up realm.close() :smile:

Closing this issue at it isn't a problem in Realm as such. The above should give you an idea about what to look after. If you are still having problems, we really need the full project or a sample project to be able to help.

@engr-erum your codes aren't rational, for commit transaction is in if{}, may not do commitTransaction(), so it may be still in transaction for your next call

I hit this error too. Turns out that i had code that was like

Tag.createUpdateTag(tag);
synchShares();            

And both are writing to Realm. Solution was quite simple... i just had to add await on the second method.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nolanamy picture nolanamy  路  3Comments

tloshi picture tloshi  路  3Comments

harshvishu picture harshvishu  路  3Comments

bryanspano picture bryanspano  路  3Comments

mithrann picture mithrann  路  3Comments