Lưu dữ liệu

Trước khi bắt đầu

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

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

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

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

  • Thêm Firebase Unity SDK (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 bao gồm cả các tác vụ trong Bảng điều khiển của Firebase và trong dự án Unity mở của bạn (ví dụ: bạn tải các tệp cấu hình Firebase xuống từ bảng điều khiển, rồi di chuyển vào dự án Unity).

Đang lưu dữ liệu

Có 5 phương thức để ghi dữ liệu vào Cơ sở dữ liệu theo thời gian thực của Firebase:

Phương thức Các cách 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() Ghi 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 khoá duy nhất mà bạn cũng có thể sử dụng làm giá trị nhận dạng duy nhất, chẳng hạn như user-scores/<user-id>/<unique-score-id>.
UpdateChildrenAsync() Cập nhật một số khoá cho đường dẫn đã xác định mà không thay thế tất cả dữ liệu.
RunTransaction() Cập nhật những dữ liệu phức tạp có thể bị hỏng do các bản cập nhật đồng thời.

Nhận một DatabaseReference

Để ghi dữ liệu vào Cơ sở dữ liệu, bạn cần có một thực thể 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;
  }
}

Ghi, cập nhật hoặc xoá dữ liệu tại một tham chiếu

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 cụ thể, thay thế mọi dữ liệu hiện có tại đường dẫn đó. Bạn có thể dùng để truyền các loại tương ứng với loại JSON có sẵn như sau:

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

Nếu sử dụng đối tượng C# đã nhập, bạn có thể dùng JsonUtility.ToJson() tích hợp sẵn để 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 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 có 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 cả mọi nút con. Tuy nhiên, bạn vẫn có thể cập nhật phần tử 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 mình, 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 một danh sách trong các ứng dụng nhiều người dùng. Phương thức Push() tạo một khoá duy nhất mỗi khi có một khoá mới con sẽ được thêm vào tham chiếu Firebase được chỉ định. Bằng cách sử dụng khoá được tạo tự động cho từng phần tử mới trong danh sách, một số khách hàng có thể thêm 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. Chiến lược phát hành đĩa đơn khoá duy nhất do Push() tạo dựa trên dấu thời gian, vì vậy các mục trong danh sách tự động sắp xếp theo trình tự thời gian.

Bạn có thể sử dụng thông tin tham chiếu đến dữ liệu mới được phương thức Push() trả về để lấy giá trị của khoá được tạo tự động hoặc đặt dữ liệu cho nhà xuất bản con. Gọi điện Key trên tham chiếu Push() trả về giá trị của khoá được tạo tự động.

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

Để ghi đồng thời vào các phần tử con cụ thể của một nút mà không ghi đè lên các nút khác nút con, 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 khoá. 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 ngừng sử dụng dữ liệu. Ví dụ: một trò chơi có thể có lớp LeaderboardEntry như sau:

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 một Mục nhập trên bảng xếp hạng và đồng thời cập nhật Mục nhập đó thành điểm số gần đây nguồn cấp dữ liệu và danh sách điểm số của riêng người dùng, trò chơi sẽ 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à truy xuất khoá đồng thời bằng Key. Sau đó, khoá này có thể được dùng để tạo mục nhập thứ hai trong tài khoản điểm số tại /user-scores/$userid/$key.

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

Xóa dữ liệu

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

Bạn cũng có thể xoá bằng cách chỉ định null làm giá trị cho lần ghi khác chẳng hạn như SetValueAsync() hoặc UpdateChildrenAsync(). Bạn có thể dùng kỹ thuật dùng UpdateChildrenAsync() để xoá nhiều phần tử con trong một 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 theo thời gian thực Firebase, bạn có thể thêm một dấu tiếp tục. Cả SetValueAsync()UpdateChildrenAsync() trả về 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ì, IsFaulted của Tasks sẽ hiển thị 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 đồng thời sửa đổi, chẳng hạn như bộ đếm tăng dần, bạn có thể sử dụng hoạt động giao dịch. Bạn cung cấp Func cho thao tác này. Nội dung cập nhật này Func sẽ sử dụng 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 khách hàng khác ghi vào vị trí đó trước khi giá trị mới của bạn là thành công, hàm cập nhật của bạn sẽ được gọi lại bằng giá trị hiện tại và việc ghi đượ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 bằng 5 điểm số 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 lệch nếu có nhiều người dùng ghi lại điểm số cùng lúc hoặc ứng dụng có dữ liệu lỗi thời. Nếu giao dịch bị từ chối, máy chủ trả về giá trị hiện tại cho máy khách, Thao tác này sẽ chạy lại giao dịch với giá trị được cập nhật. Thao tác này lặp lại cho đến khi giao dịch được chấp nhận hoặc bạn đã thử quá nhiều lần.

Ghi dữ liệu khi không có mạng

Nếu máy khách bị mất kết nối mạng, ứng dụng của bạn sẽ tiếp tục hoạt động chính xác.

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

Do đó, tất cả hoạt động 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 mọi dữ liệu đều được ghi vào máy chủ. Tức là ứng dụng của bạn vẫn hoạt động thích ứng bất kể độ trễ hoặc khả năng kết nối mạng như thế nào.

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 các sự kiện để máy khách đồng bộ hóa với trạng thái máy chủ hiện tại mà không phải viết bất kỳ mã tuỳ chỉnh nào.

Các bước tiếp theo