Lưu dữ liệu

Trước khi bắt đầu

Trước khi có thể sử dụng Cơ sở dữ liệu thời gian thực , bạn cần:

  • Đăng ký dự án Unity của bạn và định cấu hình nó để sử dụng Firebase.

    • Nếu dự án Unity của bạn đã sử dụng Firebase thì dự án đó đã được đăng ký và định cấu hình cho Firebase.

    • Nếu bạn không có dự án Unity, bạn có thể tải xuống ứng dụng mẫu .

  • Thêm SDK Unity Firebase (cụ thể là FirebaseDatabase.unitypackage ) vào dự án Unity của bạn.

Lưu ý rằng việc thêm Firebase vào dự án Unity của bạn bao gồm các nhiệm vụ cả trong bảng điều khiển Firebase và trong dự án Unity mở của bạn (ví dụ: bạn tải xuống tệp cấu hình Firebase từ bảng điều khiển, sau đó chuyển chúng vào dự án Unity của bạn).

Lưu dữ liệu

Có năm phương pháp ghi dữ liệu vào Cơ sở dữ liệu thời gian thực Firebase:

Phương pháp Sử dụng phổ biến
SetValueAsync() Ghi hoặc thay thế dữ liệu vào một đường dẫn đã xác định, chẳng hạn như users/<user-id>/<username> .
SetRawJsonValueAsync() Viết hoặc thay thế dữ liệu bằng Json thô, chẳng hạn như users/<user-id>/<username> .
Push() Thêm vào danh sách dữ liệu. Mỗi khi bạn gọi Push() , Firebase sẽ tạo một khóa duy nhất cũng có thể được sử dụng làm mã định danh duy nhất, chẳng hạn như user-scores/<user-id>/<unique-score-id> .
UpdateChildrenAsync() Cập nhật một số khóa cho đường dẫn đã xác định mà không thay thế tất cả dữ liệu.
RunTransaction() Cập nhật dữ liệu phức tạp có thể bị hỏng do cập nhật đồng thời.

Nhận một tài liệu tham khảo cơ sở dữ liệu

Để ghi dữ liệu vào Cơ sở dữ liệu, bạn cần một phiên bản của DatabaseReference :

using Firebase;
using Firebase.Database;

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

Viết, cập nhật hoặc xóa dữ liệu tại một tham chiếu

Các thao tác ghi cơ bản

Đối với các thao tác ghi cơ bản, bạn có thể sử dụng SetValueAsync() để lưu dữ liệu vào một tham chiếu đã chỉ định, thay thế mọi dữ liệu hiện có tại đường dẫn đó. Bạn có thể sử dụng phương thức này để truyền các loại tương ứng với các loại JSON có sẵn như sau:

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

Nếu bạn sử dụng đối tượng C# đã nhập, bạn có thể sử dụng JsonUtility.ToJson() tích hợp để chuyển đổi đối tượng thành Json thô và gọi SetRawJsonValueAsync() . Ví dụ: bạn có thể có một lớp Người dùng trông như sau:

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

Bạn có thể thêm người dùng bằng SetRawJsonValueAsync() như sau:

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

Việc sử dụng SetValueAsync() hoặc SetRawJsonValueAsync() theo cách này sẽ ghi đè dữ liệu tại vị trí đã chỉ định, bao gồm mọi nút con. Tuy nhiên, bạn vẫn có thể cập nhật một đối tượng con mà không cần viết lại toàn bộ đối tượng. Nếu bạn muốn cho phép người dùng cập nhật hồ sơ của họ, bạn có thể cập nhật tên người dùng như sau:

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

Thêm vào danh sách dữ liệu

Sử dụng phương thức Push() để nối dữ liệu vào danh sách trong các ứng dụng nhiều người dùng. Phương thức Push() tạo một khóa duy nhất mỗi khi một phần tử con mới được thêm vào tham chiếu Firebase đã chỉ định. Bằng cách sử dụng các khóa được tạo tự động này cho từng thành phần mới trong danh sách, một số khách hàng có thể thêm các thành phần con vào cùng một vị trí cùng lúc mà không bị xung đột khi ghi. Khóa duy nhất được tạo bởi Push() dựa trên dấu thời gian, do đó các mục trong danh sách sẽ tự động được sắp xếp theo thứ tự thời gian.

Bạn có thể sử dụng tham chiếu đến dữ liệu mới được phương thức Push() trả về để lấy giá trị của khóa được tạo tự động hoặc dữ liệu tập hợp cho trẻ. Key gọi trên tham chiếu Push() trả về giá trị của khóa được tạo tự động.

Cập nhật các trường cụ thể

Để ghi đồng thời vào các nút con cụ thể của một nút mà không ghi đè lên các nút con khác, hãy sử dụng phương thức UpdateChildrenAsync() .

Khi gọi UpdateChildrenAsync() , bạn có thể cập nhật các giá trị con cấp thấp hơn bằng cách chỉ định đường dẫn cho khóa. Nếu dữ liệu được lưu trữ ở nhiều vị trí để mở rộng quy mô tốt hơn, bạn có thể cập nhật tất cả các phiên bản của dữ liệu đó bằng cách sử dụng phân xuất dữ liệu . Ví dụ: một trò chơi có thể có lớp LeaderboardEntry như thế này:

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary<string, Object> ToDictionary() {
        Dictionary<string, Object> result = new Dictionary<string, Object>();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

Để tạo Bảng xếp hạng và đồng thời cập nhật nó lên nguồn cấp dữ liệu điểm số gần đây cũng như danh sách điểm số của chính người dùng, trò chơi sử dụng mã như sau:

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary<string, Object> entryValues = entry.ToDictionary();

    Dictionary<string, Object> childUpdates = new Dictionary<string, Object>();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

Ví dụ này sử dụng Push() để tạo một mục nhập trong nút chứa các mục nhập cho tất cả người dùng tại /scores/$key và đồng thời truy xuất khóa bằng Key . Sau đó, khóa này có thể được sử dụng để tạo mục nhập thứ hai về điểm số của người dùng tại /user-scores/$userid/$key .

Bằng cách sử dụng các đường dẫn này, bạn có thể thực hiện cập nhật đồng thời cho nhiều vị trí trong cây JSON bằng một lệnh gọi tới UpdateChildrenAsync() , chẳng hạn như cách ví dụ này tạo mục nhập mới ở cả hai vị trí. Các bản cập nhật đồng thời được thực hiện theo cách này mang tính nguyên tử: tất cả các bản cập nhật đều thành công hoặc tất cả các bản cập nhật đều không thành công.

Xóa dữ liệu

Cách đơn giản nhất để xóa dữ liệu là gọi RemoveValue() trên tham chiếu đến vị trí của dữ liệu đó.

Bạn cũng có thể xóa bằng cách chỉ định null làm giá trị cho thao tác ghi khác, chẳng hạn như SetValueAsync() hoặc UpdateChildrenAsync() . Bạn có thể sử dụng kỹ thuật này với UpdateChildrenAsync() để xóa nhiều thành phần con trong một lệnh gọi API.

Biết khi nào dữ liệu của bạn được cam kết.

Để biết thời điểm dữ liệu của bạn được cam kết với máy chủ Cơ sở dữ liệu thời gian thực Firebase, bạn có thể thêm phần tiếp theo. Cả SetValueAsync()UpdateChildrenAsync() đều trả về một Task cho phép bạn biết khi nào thao tác hoàn tất. Nếu cuộc gọi không thành công vì bất kỳ lý do gì, Nhiệm vụ IsFaulted sẽ đúng với thuộc tính Exception cho biết lý do xảy ra lỗi.

Lưu dữ liệu dưới dạng giao dịch

Khi làm việc với dữ liệu có thể bị hỏng do sửa đổi đồng thời, chẳng hạn như bộ đếm tăng dần, bạn có thể sử dụng thao tác giao dịch . Bạn gán cho thao tác này một Func . Bản cập nhật này Func lấy trạng thái hiện tại của dữ liệu làm đối số và trả về trạng thái mong muốn mới mà bạn muốn ghi. Nếu một ứng dụng khách khác ghi vào vị trí trước khi giá trị mới của bạn được ghi thành công, hàm cập nhật của bạn sẽ được gọi lại với giá trị hiện tại mới và quá trình ghi sẽ được thử lại.

Ví dụ: trong một trò chơi, bạn có thể cho phép người dùng cập nhật bảng xếp hạng với năm điểm cao nhất:

private void AddScoreToLeaders(string email, 
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData => {
      List<object> leaders = mutableData.Value as List<object>

      if (leaders == null) {
        leaders = new List<object>();
      } else if (mutableData.ChildrenCount >= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary<string, object>)) continue;
          long childScore = (long)
                      ((Dictionary<string, object>)child)["score"];
          if (childScore < minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore > score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

        // Remove the lowest score.
        leaders.Remove(minVal);
      }

      // Add the new high score.
      Dictionary<string, object> newScoreMap =
                       new Dictionary<string, object>();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

Việc sử dụng giao dịch sẽ giúp bảng xếp hạng không bị sai nếu nhiều người dùng ghi điểm cùng lúc hoặc khách hàng có dữ liệu cũ. Nếu giao dịch bị từ chối, máy chủ sẽ trả về giá trị hiện tại cho khách hàng, máy khách sẽ chạy lại giao dịch với giá trị được cập nhật. Điều này lặp lại cho đến khi giao dịch được chấp nhận hoặc đã thực hiện quá nhiều lần thử.

Ghi dữ liệu ngoại tuyến

Nếu khách hàng mất kết nối mạng, ứng dụng của bạn sẽ tiếp tục hoạt động bình thường.

Mỗi khách hàng được kết nối với cơ sở dữ liệu Firebase sẽ duy trì phiên bản nội bộ của bất kỳ dữ liệu đang hoạt động nào. Khi dữ liệu được ghi, trước tiên nó sẽ được ghi vào phiên bản cục bộ này. Sau đó, ứng dụng khách Firebase sẽ đồng bộ hóa dữ liệu đó với các máy chủ cơ sở dữ liệu từ xa và với các ứng dụng khách khác trên cơ sở "nỗ lực tối đa".

Kết quả là, tất cả các thao tác ghi vào cơ sở dữ liệu sẽ kích hoạt các sự kiện cục bộ ngay lập tức trước khi bất kỳ dữ liệu nào được ghi vào máy chủ. Điều này có nghĩa là ứng dụng của bạn vẫn phản hồi bất kể độ trễ mạng hoặc khả năng kết nối.

Sau khi kết nối được thiết lập lại, ứng dụng của bạn sẽ nhận được nhóm sự kiện thích hợp để ứng dụng khách đồng bộ hóa với trạng thái máy chủ hiện tại mà không cần phải viết bất kỳ mã tùy chỉnh nào.

Bước tiếp theo