【问题标题】:Realm exception "nested transaction not allowed" even though there are no nested transactions即使没有嵌套事务,领域异常“不允许嵌套事务”
【发布时间】:2016-10-24 18:50:02
【问题描述】:

最近我开始了一个安卓应用项目。我需要尽可能结构化地管理数据。

所以我选择了领域并对其进行了一些修改。

但我遇到了一些错误。但是我不知道为什么会发生这个错误。

错误是

不允许嵌套事务。在每个 beginTransaction() 之后使用 commitTransaction()。

我的代码在下面。

public class CuratorApplication extends Application {

    private Realm realm;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("debug", "Application class create!!");
        configureRealmDatabase(this);
    }

    private void configureRealmDatabase(Context context){
        RealmConfiguration config = new RealmConfiguration.Builder(context)
                .name("curator.realm")
                .build();
        Realm.setDefaultConfiguration(config);
    }
}

here 中所述,我在Application 类中注册领域

我尝试在活动中进行交易。但它显示错误。 :(

package com.nolgong.curator.screen;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.nolgong.curator.R;
import com.nolgong.curator.model.retrofit.Game;
import com.nolgong.curator.model.retrofit.GameInformation;
import com.nolgong.curator.model.retrofit.Team;
import com.nolgong.curator.network.NetworkClient;

import java.io.IOException;
import java.util.Properties;

import io.realm.Realm;
import io.realm.exceptions.RealmPrimaryKeyConstraintException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class IntroActivity extends AppCompatActivity {

    private Button confirmBtn;
    private EditText confirmText;
    private Realm realm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intro);
        setUp();
        registerListener();
    }

    private String getProperty() throws IOException{
        Properties properties = new Properties();
        properties.load(getResources().openRawResource(R.raw.config));
        String property = properties.getProperty("serverAddress");
        Log.e("debug", "Property : " + property);
        return property;
    }

    private void setNetworkClient(String serverAddress){
        Log.e("debug", "Address : " + serverAddress);
        NetworkClient.getInstance(serverAddress);
    }

    private void setUp(){
        try {
            setNetworkClient(getProperty());
        } catch (IOException e){
            Log.e("debug", "set network" + e);
        }
        confirmBtn = (Button)findViewById(R.id.intro_confirm);
        confirmText = (EditText)findViewById(R.id.intro_input);
        realm = Realm.getDefaultInstance();
        Log.e("debug", "transaction state : " + realm.isInTransaction());
        Log.e("debug", "CONFIGURATION : \n" + realm.getConfiguration());
    }

    private void registerListener(){
        confirmBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String teamId = confirmText.getText().toString();
                Integer digit = Integer.valueOf(teamId);
                Log.e("debug", digit + "");
                NetworkClient.getInstance().login(digit, new Callback<GameInformation>() {
                    @Override
                    public void onResponse(Call<GameInformation> call, Response<GameInformation> response) {
                        int responseCode = response.code();
                        switch (responseCode){
                            case 200:
                                GameInformation gameInformation = response.body();

                                Log.e("debug", "game information " + gameInformation.toString());

                                Game game = gameInformation.getGame();
                                Team team = gameInformation.getTeam();

                                updateGameToRealm(game);
                                updateTeamToRealm(team);
                                break;
                            default:
                                Log.e("debug", "Maybe something happened.");
                                break;
                        }
                    }

                    @Override
                    public void onFailure(Call<GameInformation> call, Throwable t) {
                        Log.e("debug", "Login fail :" + t.toString());
                    }
                });
            }
        });
    }

    private void updateGameToRealm(Game game){

        com.nolgong.curator.model.database.Game rGame = new com.nolgong.
                curator.model.database.Game(game.getId(), game.getDate(),
                game.getSession(), game.getRunningTime());
        realm.beginTransaction();

        try {
            realm.copyToRealm(rGame);
        } catch (RealmPrimaryKeyConstraintException e){
            Log.e("debug", e.toString());
            realm.cancelTransaction();
        } finally {
            realm.commitTransaction();
        }
    }

    private void updateTeamToRealm(Team team){
        com.nolgong.curator.model.database.Team rTeam = new com.nolgong.
                curator.model.database.Team(team.getId(), team.getMembers(),
                team.getGameId(), team.isClientDataSynced(),
                team.getJob(), team.getDigit(),
                team.getPoint());
        realm.beginTransaction();
        try {
            realm.copyToRealm(rTeam);
        } catch (RealmPrimaryKeyConstraintException e){
            Log.e("debug", e.toString());
            realm.cancelTransaction();
        } finally {
            realm.commitTransaction();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}

为什么领域显示错误?我正确使用了吗?或者这只是一个错误? 请帮帮我ioi..

【问题讨论】:

  • 你能显示与错误相关的代码吗?
  • 您在代码中某处连续调用beginTransaction() 两次,但此处未引用。
  • 如果某处有循环,请在循环外开始事务,然后在循环结束后提交;还使用常规 for() 循环而不是 foreach
  • @Eenvincible 从技术上讲 foreach 现在可以在 RealmResults 上正常工作,因为 0.89.0 启用了“正确的迭代行为”,但是是的。
  • 糟糕!我忘了更改代码。现在我更改了源代码。

标签: android realm


【解决方案1】:

正如错误所说,

不允许嵌套事务。在每个 beginTransaction() 之后使用 commitTransaction()。

这意味着你不能做这样的事情:

realm.beginTransaction();
...
realm.beginTransaction();
realm.commitTransaction();

beginTransaction() 调用后必须跟 commitTransaction()cancelTransaction() 调用。

还强烈建议使用executeTransaction() 而不是begin/cancel/commit,因为它更易于使用,并且会自动为您处理异常取消。

编辑:在使用cancelTransaction() 回滚后,您不应提交事务。

请尝试将begin/cancel/commit 替换为executeTransaction(),看看会发生什么。

另外,您可以尝试将copyToRealm() 替换为copyToRealmOrUpdate()

我认为您可能会遇到this issue,因为您遇到了失败的 UI 线程上的多个事务,但实际上我不确定。

EDIT2:

private void updateGameToRealm(Game game){
    Realm realm = null;
    try {
        realm = Realm.getDefaultInstance();
        final com.nolgong.curator.model.database.Game rGame = new com.nolgong.
            curator.model.database.Game(game.getId(), game.getDate(),
            game.getSession(), game.getRunningTime());
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(rGame);
            }
        });
    } finally {
        if(realm != null) {
            realm.close();
        }
    }
}

private void updateTeamToRealm(Team team){
    Realm realm = null;
    try {      
        realm = Realm.getDefaultInstance();
        final com.nolgong.curator.model.database.Team rTeam = new com.nolgong.
            curator.model.database.Team(team.getId(), team.getMembers(),
            team.getGameId(), team.isClientDataSynced(),
            team.getJob(), team.getDigit(),
            team.getPoint());
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(rTeam);
            }
        });
    } finally {
        if(realm != null) {
            realm.close();
        }
    }
}

【讨论】:

  • 在 commitTransaction() 之前我没有使用 beginTrasaction() 两次。所以这就是我混淆它的原因。
  • 我将评论移到了答案中
  • 我将 begin/cancel/commit 更改为 executeTransaction()。但是它也说Nested transactions are not allowed. Use commitTransaction() after each beginTransaction().我按照你说的改了交易码。
  • realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm tRealm) { com.nolgong.curator.model.database.Game rGame = new com.nolgong. curator.model.database.Game(game.getId(), game.getDate(), game.getSession(), game.getRunningTime()); tRealm.copyToRealm(rGame); } });
  • 感谢史诗!我终于得到了错误。在代码活动的其他部分关闭而事务关闭。当我更改您推荐的代码样式时,我解决了问题!
【解决方案2】:

问题在这里:https://github.com/realm/realm-java/issues/542

您的领域交易代码应如下所示:

Realm realm = Realm.getInstance(getApplicationContext());

                    //Writing to Realm with Transaction blocks
                    realm.beginTransaction();

                    ModelClass modelClass = realm.createObject(ModelClass.class);

                    // increment index
                    long nextID = (long) (realm.where(ModelClass.class).max("id"));
                    long primaryKeyValue = nextID + 1;

                    try {
                        modelClass.setId(primaryKeyValue);
                        //your can set other values
                        realm.commitTransaction();

                    } catch (Exception e) {
                        Log.e("Realm Error", "error" + e.getLocalizedMessage());
                        realm.cancelTransaction();
                    }

【讨论】:

    【解决方案3】:

    据我所知,最好的解决方案是在 realm.executeTransactionAsync 方法 relam 处理开始事务,提交事务本身,如果你使用这个 executeTransactionAsync 方法

    我在插入或更新数据时也遇到了同样的错误,然后我找到了这个方法, 以下是我使用的示例

    public void saveUserInfo(final UserDto userDto){

        realm = Realm.getDefaultInstance();
        realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm = Realm.getDefaultInstance();
                realm.copyToRealmOrUpdate(userDto);
                //realm.commitTransaction();
            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                EventBus.getDefault().post(new OnUserSaveEvent(true));
                realm.close();
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable error) {
                realm.close();
            }
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-30
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-09
      • 2014-12-12
      相关资源
      最近更新 更多