Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Firebase如何防止原子级重复条目_Firebase_Transactions_Firebase Realtime Database_Atomic - Fatal编程技术网

Firebase如何防止原子级重复条目

Firebase如何防止原子级重复条目,firebase,transactions,firebase-realtime-database,atomic,Firebase,Transactions,Firebase Realtime Database,Atomic,我正在考虑使用firebase作为web应用程序用户数据的数据存储。我目前的想法是使用每个用户加入时的时间戳作为引用该用户数据的键来存储每个用户的数据。此方案的优点是,它是一种为用户分配唯一整数ID的简单方法,并且使用户的时间排序变得简单 然而,一个缺点是,如果两个adduser请求使用相同的数据提交,应用程序将很高兴地添加两个单独的条目,这就是unideal。我可以随意改变事情(我开始认为我应该使用电子邮件作为关键,并通过加入数据来确定优先级,而不是我当前的方案),但假设我不想这样做。有没有办

我正在考虑使用firebase作为web应用程序用户数据的数据存储。我目前的想法是使用每个用户加入时的时间戳作为引用该用户数据的键来存储每个用户的数据。此方案的优点是,它是一种为用户分配唯一整数ID的简单方法,并且使用户的时间排序变得简单

然而,一个缺点是,如果两个
adduser
请求使用相同的数据提交,应用程序将很高兴地添加两个单独的条目,这就是unideal。我可以随意改变事情(我开始认为我应该使用电子邮件作为关键,并通过加入数据来确定优先级,而不是我当前的方案),但假设我不想这样做。有没有办法防止重复数据

天真的方法可能只是做如下事情:

if(!searchFirebaseForUser(data)) {
    addUser(data);
}

但这绝对是一种竞赛条件;两个请求都可以很容易地查询并在数据库中找不到用户,并且都可以添加。我希望在事务中这样做,但Firebase事务支持似乎没有涵盖这种情况。有什么方法可以处理这个问题吗?

您可以使用
推送
自动生成按时间顺序递增的ID,即使它们是同时创建的,也不会与其他客户端发生冲突(其中包含随机组件)

例如:

var ref=新Firebase(URL);
var记录=参考推送(用户信息);
console.log(“为用户分配了ID:+record.name());

您可能必须使用用户名或电子邮件地址作为密钥,并尝试以原子方式写入该位置

下面是函数参考中的相关代码示例。在这种情况下,我们使用
wilma
作为用户的密钥

//尝试为wilma创建用户,但前提是用户id“wilma”尚未获取。
var wilmaRef=新的火基('https://SampleChat.firebaseIO-demo.com/users/wilma');
wilmaRef.事务(函数(currentData){
如果(currentData==null){
返回{name:{第一个:'Wilma',最后一个:'Flintstone'};
}否则{
log('用户wilma已经存在');
return;//中止事务。
}
},函数(错误、已提交、快照){
如果(错误)
console.log('事务异常失败!',错误);
否则,如果(!已提交)
log('我们中止了事务(因为wilma已经存在)。';
其他的
log('User wilma added!');
log('Wilma's data:',snapshot.val());
});

安全规则是否不足以强制唯一性?我不知道它们是否是原子的

{
    "rules": {
        "users": {
            "$username": {
                ".write": "!data.exists()"
            }
        }
    }
}

避免重复条目的最简单方法不是在fire base数据库中定义规则,而是首先从fire base数据库获取所有数据,并将其与要存储的数据(新数据)进行比较,如果它与以前的数据匹配,则再次放弃存储在数据库中,否则存储在数据库中。请检查以下内容以了解更多信息

public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private BroadcastReceiver mRegistrationBroadcastReceiver;
private TextView txtRegId, txtMessage;
DatabaseReference databaseArtists;
ListView listViewArtists;
public static String regId;
List<Artist> artistList;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
txtRegId = (TextView) findViewById(R.id.regid);
txtRegId.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            displayFirebaseRegId();
            boolean flag=false;
            String tokenId=regId;
            for(Artist a:artistList)
            {Log.d("RAaz",a.getTokenId()+"    "+tokenId);
                if(a.getTokenId().equalsIgnoreCase(tokenId))
                {
                    flag=true;
                    Toast.makeText(MainActivity.this, "True", Toast.LENGTH_SHORT).show();
                }
            }
            if(flag)
            {
                Toast.makeText(MainActivity.this, "User Already Exists", Toast.LENGTH_SHORT).show();
            }
            else {
                addArtist();
            }
        }
    });
    mRegistrationBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // checking for type intent filter
            if (intent.getAction().equals(Config.REGISTRATION_COMPLETE)) {
                // gcm successfully registered
                // now subscribe to `global` topic to receive app wide notifications
                FirebaseMessaging.getInstance().subscribeToTopic(Config.TOPIC_GLOBAL);
                displayFirebaseRegId();
            } else if (intent.getAction().equals(Config.PUSH_NOTIFICATION)) {
                // new push notification is received
                String message = intent.getStringExtra("message");
                Toast.makeText(getApplicationContext(), "Push notification: " + message, Toast.LENGTH_LONG).show();
                txtMessage.setText(message);
            }
        }
    };
    displayFirebaseRegId();
    databaseArtists = FirebaseDatabase.getInstance().getReference("artist");
    artistList = new ArrayList<>();}
使用onStart从firebase数据库获取详细信息

protected void onStart() {
    super.onStart();
    Toast.makeText(this, "On Start", Toast.LENGTH_SHORT).show();
    databaseArtists.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            artistList.clear();
            for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
                Artist artist = dataSnapshot1.getValue(Artist.class);
                artistList.add(artist);
            }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
        }
    });
}
最后添加pojo类

public class Artist {
private String artistId;
private String tokenId;
private String roleName;

public Artist() {
}

public Artist(String artistId, String tokenId, String roleName) {
    this.artistId = artistId;
    this.tokenId = tokenId;
    this.roleName = roleName;
}

public String getArtistId() {
    return artistId;
}

public void setArtistId(String artistId) {
    this.artistId = artistId;
}

public String getTokenId() {
    return tokenId;
}

public void setTokenId(String tokenId) {
    this.tokenId = tokenId;
}

public String getRoleName() {
    return roleName;
}

public void setRoleName(String roleName) {
    this.roleName = roleName;
}

}

这里有两件事:如果同一用户被添加两次,我认为这不会解决我的问题。我的问题是,我不希望两个相同的条目只在ID上有所不同。另一方面,我避免使用push的原因是它提供了非数字ID,因为它必须与其他组件配合使用,这些组件将假定用户ID是数字的。啊,明白了。您需要使用.transaction()来分配唯一的ID。这里有一个例子:这可以防止我在用户登录时写入重复的记录(当用户手动单击我的应用程序上的登录按钮时,我会在用户表中创建一条记录)。我在Firebase文档中介绍了如何在不使用自定义登录的情况下创建单独的用户表(在我的例子中是Facebook):不起作用。这段代码的作用是避免在用户名中写入已经写入的内容。这个答案的问题是,检查和插入操作不是原子的-当两个用户决定在大致相同的时间选择相同的名称时,存在竞争条件。假设两个用户同时执行检查//if(a.getTokenId().equalsIgnoreCase(tokenId))//时,两个用户都将返回false。因为两个用户都尚未将其令牌ID插入数据存储。因此,将执行两个用户的插入逻辑,最后一个执行插入的人将获胜。
public class Artist {
private String artistId;
private String tokenId;
private String roleName;

public Artist() {
}

public Artist(String artistId, String tokenId, String roleName) {
    this.artistId = artistId;
    this.tokenId = tokenId;
    this.roleName = roleName;
}

public String getArtistId() {
    return artistId;
}

public void setArtistId(String artistId) {
    this.artistId = artistId;
}

public String getTokenId() {
    return tokenId;
}

public void setTokenId(String tokenId) {
    this.tokenId = tokenId;
}

public String getRoleName() {
    return roleName;
}

public void setRoleName(String roleName) {
    this.roleName = roleName;
}