Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

บันทึกข้อมูล

เอกสารนี้ครอบคลุมสี่วิธีในการเขียนข้อมูลไปยังฐานข้อมูลเรียลไทม์ของ Firebase: ตั้งค่า อัปเดต พุช และรองรับธุรกรรม

วิธีบันทึกข้อมูล

ชุด เขียนหรือเปลี่ยนข้อมูลไปยังเส้นทางที่กำหนดไว้เช่น messages/users/<username>
อัปเดต อัปเดตคีย์บางอันสำหรับพาธที่กำหนดโดยไม่ต้องแทนที่ data ทั้งหมด
ดัน เพิ่มในรายการของข้อมูลในฐานข้อมูล เวลาที่คุณผลักดันโหนดใหม่ลงในรายการทุกฐานข้อมูลของคุณสร้างคีย์ที่ไม่ซ้ำกันเช่น messages/users/<unique-user-id>/<username>
ธุรกรรม ใช้ธุรกรรมเมื่อทำงานกับข้อมูลที่ซับซ้อนที่อาจเสียหายจากการอัพเดทพร้อมกัน

บันทึกข้อมูล

การดำเนินการเขียนฐานข้อมูลพื้นฐานคือชุดที่บันทึกข้อมูลใหม่ไปยังการอ้างอิงฐานข้อมูลที่ระบุ โดยแทนที่ข้อมูลที่มีอยู่ที่พาธนั้น เพื่อให้เข้าใจการตั้งค่า เราจะสร้างแอปบล็อกง่ายๆ ข้อมูลสำหรับแอปของคุณถูกเก็บไว้ที่การอ้างอิงฐานข้อมูลนี้:

Java
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("server/saving-data/fireblog");
Node.js
// Import Admin SDK
const { getDatabase } = require('firebase-admin/database');

// Get a database reference to our blog
const db = getDatabase();
const ref = db.ref('server/saving-data/fireblog');
Python
# Import database module.
from firebase_admin import db

# Get a database reference to our blog.
ref = db.reference('server/saving-data/fireblog')
ไป
// Create a database client from App.
client, err := app.Database(ctx)
if err != nil {
	log.Fatalln("Error initializing database client:", err)
}

// Get a database reference to our blog.
ref := client.NewRef("server/saving-data/fireblog")

เริ่มต้นด้วยการบันทึกข้อมูลผู้ใช้บางส่วน เราจะจัดเก็บผู้ใช้แต่ละคนด้วยชื่อผู้ใช้ที่ไม่ซ้ำกัน และเราจะจัดเก็บชื่อเต็มและวันเกิดของพวกเขาด้วย เนื่องจากผู้ใช้แต่ละคนจะมีชื่อผู้ใช้ที่ไม่ซ้ำกัน จึงควรใช้วิธีการตั้งค่าที่นี่แทนวิธีพุช เนื่องจากคุณมีคีย์อยู่แล้วและไม่จำเป็นต้องสร้างใหม่

ขั้นแรก สร้างการอ้างอิงฐานข้อมูลไปยังข้อมูลผู้ใช้ของคุณ แล้วใช้ set() / setValue() เพื่อบันทึกวัตถุผู้ใช้ไปยังฐานข้อมูลด้วยชื่อผู้ใช้ของผู้ใช้ชื่อเต็มและวันเกิด คุณสามารถผ่านการตั้งค่าสตริงจำนวนบูล, null อาร์เรย์หรือวัตถุใด ๆ JSON ผ่าน null จะลบข้อมูลในตำแหน่งที่ระบุ ในกรณีนี้ คุณจะส่งผ่านวัตถุ:

Java
public static class User {

  public String date_of_birth;
  public String full_name;
  public String nickname;

  public User(String dateOfBirth, String fullName) {
    // ...
  }

  public User(String dateOfBirth, String fullName, String nickname) {
    // ...
  }

}

DatabaseReference usersRef = ref.child("users");

Map<String, User> users = new HashMap<>();
users.put("alanisawesome", new User("June 23, 1912", "Alan Turing"));
users.put("gracehop", new User("December 9, 1906", "Grace Hopper"));

usersRef.setValueAsync(users);
Node.js
const usersRef = ref.child('users');
usersRef.set({
  alanisawesome: {
    date_of_birth: 'June 23, 1912',
    full_name: 'Alan Turing'
  },
  gracehop: {
    date_of_birth: 'December 9, 1906',
    full_name: 'Grace Hopper'
  }
});
Python
users_ref = ref.child('users')
users_ref.set({
    'alanisawesome': {
        'date_of_birth': 'June 23, 1912',
        'full_name': 'Alan Turing'
    },
    'gracehop': {
        'date_of_birth': 'December 9, 1906',
        'full_name': 'Grace Hopper'
    }
})
ไป

// User is a json-serializable type.
type User struct {
	DateOfBirth string `json:"date_of_birth,omitempty"`
	FullName    string `json:"full_name,omitempty"`
	Nickname    string `json:"nickname,omitempty"`
}

usersRef := ref.Child("users")
err := usersRef.Set(ctx, map[string]*User{
	"alanisawesome": {
		DateOfBirth: "June 23, 1912",
		FullName:    "Alan Turing",
	},
	"gracehop": {
		DateOfBirth: "December 9, 1906",
		FullName:    "Grace Hopper",
	},
})
if err != nil {
	log.Fatalln("Error setting value:", err)
}

เมื่ออ็อบเจ็กต์ JSON ถูกบันทึกลงในฐานข้อมูล คุณสมบัติอ็อบเจ็กต์จะถูกแมปโดยอัตโนมัติไปยังตำแหน่งย่อยของฐานข้อมูลในลักษณะที่ซ้อนกัน ตอนนี้ถ้าคุณนำทางไปยัง URL https://docs-examples.firebaseio.com/server/saving-data/fireblog/users/alanisawesome/full_name เราจะเห็นค่า "อลันทัวริง" คุณยังสามารถบันทึกข้อมูลไปยังตำแหน่งย่อยได้โดยตรง:

Java
usersRef.child("alanisawesome").setValueAsync(new User("June 23, 1912", "Alan Turing"));
usersRef.child("gracehop").setValueAsync(new User("December 9, 1906", "Grace Hopper"));
Node.js
const usersRef = ref.child('users');
usersRef.child('alanisawesome').set({
  date_of_birth: 'June 23, 1912',
  full_name: 'Alan Turing'
});
usersRef.child('gracehop').set({
  date_of_birth: 'December 9, 1906',
  full_name: 'Grace Hopper'
});
Python
users_ref.child('alanisawesome').set({
    'date_of_birth': 'June 23, 1912',
    'full_name': 'Alan Turing'
})
users_ref.child('gracehop').set({
    'date_of_birth': 'December 9, 1906',
    'full_name': 'Grace Hopper'
})
ไป
if err := usersRef.Child("alanisawesome").Set(ctx, &User{
	DateOfBirth: "June 23, 1912",
	FullName:    "Alan Turing",
}); err != nil {
	log.Fatalln("Error setting value:", err)
}

if err := usersRef.Child("gracehop").Set(ctx, &User{
	DateOfBirth: "December 9, 1906",
	FullName:    "Grace Hopper",
}); err != nil {
	log.Fatalln("Error setting value:", err)
}

สองตัวอย่างข้างต้น - การเขียนทั้งสองค่าพร้อมกันเป็นวัตถุและเขียนแยกกันไปยังตำแหน่งย่อย - จะส่งผลให้ข้อมูลเดียวกันถูกบันทึกลงในฐานข้อมูลของคุณ:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper"
    }
  }
}

ตัวอย่างแรกจะทริกเกอร์เหตุการณ์เดียวในไคลเอนต์ที่กำลังดูข้อมูล ในขณะที่ตัวอย่างที่สองจะทริกเกอร์สองเหตุการณ์ มันเป็นสิ่งสำคัญที่จะทราบว่าหากข้อมูลที่มีอยู่แล้ว usersRef , วิธีแรกจะเขียนทับมัน แต่วิธีการที่สองเท่านั้นที่จะปรับเปลี่ยนค่าของแต่ละโหนดเด็กแยกต่างหากในขณะที่ออกจากเด็กคนอื่น ๆ ของ usersRef ไม่เปลี่ยนแปลง

กำลังอัปเดตข้อมูลที่บันทึกไว้

หากคุณต้องการเขียนถึงชายน์หลายแห่งของตำแหน่งฐานข้อมูลพร้อมกันโดยไม่เขียนทับโหนดย่อยอื่น คุณสามารถใช้วิธีการอัพเดตดังที่แสดงด้านล่าง:

Java
DatabaseReference hopperRef = usersRef.child("gracehop");
Map<String, Object> hopperUpdates = new HashMap<>();
hopperUpdates.put("nickname", "Amazing Grace");

hopperRef.updateChildrenAsync(hopperUpdates);
Node.js
const usersRef = ref.child('users');
const hopperRef = usersRef.child('gracehop');
hopperRef.update({
  'nickname': 'Amazing Grace'
});
Python
hopper_ref = users_ref.child('gracehop')
hopper_ref.update({
    'nickname': 'Amazing Grace'
})
ไป
hopperRef := usersRef.Child("gracehop")
if err := hopperRef.Update(ctx, map[string]interface{}{
	"nickname": "Amazing Grace",
}); err != nil {
	log.Fatalln("Error updating child:", err)
}

การดำเนินการนี้จะอัปเดตข้อมูลของ Grace เพื่อรวมชื่อเล่นของเธอ หากคุณเคยใช้ตั้งที่นี่แทนของการปรับปรุงก็จะได้ลบทั้ง full_name และ date_of_birth จาก hopperRef

ฐานข้อมูลเรียลไทม์ของ Firebase ยังรองรับการอัปเดตหลายเส้นทาง ซึ่งหมายความว่าขณะนี้การปรับปรุงสามารถปรับปรุงค่าในสถานที่หลายแห่งในฐานข้อมูลของคุณในเวลาเดียวกัน, คุณลักษณะที่มีประสิทธิภาพซึ่งจะช่วยให้ช่วยให้คุณ denormalize ข้อมูลของคุณ การใช้การอัปเดตหลายเส้นทาง คุณสามารถเพิ่มชื่อเล่นให้กับทั้งเกรซและอลันได้พร้อมกัน:

Java
Map<String, Object> userUpdates = new HashMap<>();
userUpdates.put("alanisawesome/nickname", "Alan The Machine");
userUpdates.put("gracehop/nickname", "Amazing Grace");

usersRef.updateChildrenAsync(userUpdates);
Node.js
const usersRef = ref.child('users');
usersRef.update({
  'alanisawesome/nickname': 'Alan The Machine',
  'gracehop/nickname': 'Amazing Grace'
});
Python
users_ref.update({
    'alanisawesome/nickname': 'Alan The Machine',
    'gracehop/nickname': 'Amazing Grace'
})
ไป
if err := usersRef.Update(ctx, map[string]interface{}{
	"alanisawesome/nickname": "Alan The Machine",
	"gracehop/nickname":      "Amazing Grace",
}); err != nil {
	log.Fatalln("Error updating children:", err)
}

หลังจากอัปเดตนี้ ทั้ง Alan และ Grace ได้เพิ่มชื่อเล่นของพวกเขาแล้ว:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

โปรดทราบว่าการพยายามอัปเดตออบเจ็กต์โดยการเขียนออบเจ็กต์ที่มีพาธรวมอยู่ด้วยจะส่งผลให้มีการทำงานที่แตกต่างกัน มาดูกันว่าจะเกิดอะไรขึ้นหากคุณพยายามอัปเดต Grace และ Alan ด้วยวิธีนี้:

Java
Map<String, Object> userNicknameUpdates = new HashMap<>();
userNicknameUpdates.put("alanisawesome", new User(null, null, "Alan The Machine"));
userNicknameUpdates.put("gracehop", new User(null, null, "Amazing Grace"));

usersRef.updateChildrenAsync(userNicknameUpdates);
Node.js
const usersRef = ref.child('users');
usersRef.update({
  'alanisawesome': {
    'nickname': 'Alan The Machine'
  },
  'gracehop': {
    'nickname': 'Amazing Grace'
  }
});
Python
users_ref.update({
    'alanisawesome': {
        'nickname': 'Alan The Machine'
    },
    'gracehop': {
        'nickname': 'Amazing Grace'
    }
})
ไป
if err := usersRef.Update(ctx, map[string]interface{}{
	"alanisawesome": &User{Nickname: "Alan The Machine"},
	"gracehop":      &User{Nickname: "Amazing Grace"},
}); err != nil {
	log.Fatalln("Error updating children:", err)
}

ผลนี้ในการทำงานที่แตกต่างกันกล่าวคือการเขียนทับทั้ง /users โหนด:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

การเพิ่มการโทรกลับให้เสร็จสมบูรณ์

ใน Node.js และ Java Admin SDK หากคุณต้องการทราบว่าข้อมูลของคุณได้รับมอบหมายเมื่อใด คุณสามารถเพิ่มการเรียกกลับการเสร็จสิ้นได้ ทั้งวิธีตั้งค่าและอัปเดตใน SDK เหล่านี้ใช้การเรียกกลับการทำให้สมบูรณ์ซึ่งเป็นทางเลือกซึ่งถูกเรียกเมื่อเขียนไปยังฐานข้อมูล หากการโทรไม่สำเร็จด้วยเหตุผลบางประการ การเรียกกลับจะถูกส่งผ่านวัตถุข้อผิดพลาดที่ระบุว่าเหตุใดจึงเกิดความล้มเหลว ใน Python และ Go Admin SDK วิธีการเขียนทั้งหมดกำลังบล็อกอยู่ นั่นคือวิธีการเขียนจะไม่ส่งคืนจนกว่าการเขียนจะถูกส่งไปยังฐานข้อมูล

Java
DatabaseReference dataRef = ref.child("data");
dataRef.setValue("I'm writing data", new DatabaseReference.CompletionListener() {
  @Override
  public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
    if (databaseError != null) {
      System.out.println("Data could not be saved " + databaseError.getMessage());
    } else {
      System.out.println("Data saved successfully.");
    }
  }
});
Node.js
dataRef.set('I\'m writing data', (error) => {
  if (error) {
    console.log('Data could not be saved.' + error);
  } else {
    console.log('Data saved successfully.');
  }
});

การบันทึกรายการข้อมูล

เมื่อสร้างรายการข้อมูล สิ่งสำคัญคือต้องคำนึงถึงลักษณะผู้ใช้หลายคนของแอปพลิเคชันส่วนใหญ่ และปรับโครงสร้างรายการของคุณตามนั้น จากตัวอย่างข้างต้น มาเพิ่มบล็อกโพสต์ในแอปของคุณกัน สัญชาตญาณแรกของคุณอาจเป็นการใช้ set เพื่อจัดเก็บลูกๆ ด้วยดัชนีจำนวนเต็มแบบเพิ่มค่าอัตโนมัติ ดังตัวอย่างต่อไปนี้:

// NOT RECOMMENDED - use push() instead!
{
  "posts": {
    "0": {
      "author": "gracehop",
      "title": "Announcing COBOL, a New Programming Language"
    },
    "1": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

หากผู้ใช้เพิ่มโพสต์ใหม่มันจะถูกเก็บไว้เป็น /posts/2 2 การดำเนินการนี้จะใช้ได้หากมีผู้เขียนเพียงคนเดียวที่เพิ่มโพสต์ แต่ในแอปพลิเคชันการเขียนบล็อกที่ทำงานร่วมกัน ผู้ใช้หลายคนอาจเพิ่มโพสต์พร้อมกันได้ ถ้าสองผู้เขียนเขียนถึง /posts/2 พร้อมกันแล้วหนึ่งของโพสต์จะถูกลบออกจากคนอื่น ๆ

เพื่อแก้ปัญหานี้ลูกค้า Firebase ให้ push() ฟังก์ชั่นที่สร้างคีย์ที่ไม่ซ้ำกันสำหรับแต่ละเด็กใหม่ ด้วยการใช้คีย์ลูกที่ไม่ซ้ำกัน ลูกค้าหลายรายสามารถเพิ่มรายการย่อยไปยังตำแหน่งเดียวกันได้ในเวลาเดียวกันโดยไม่ต้องกังวลเกี่ยวกับข้อขัดแย้งในการเขียน

Java
public static class Post {

  public String author;
  public String title;

  public Post(String author, String title) {
    // ...
  }

}

DatabaseReference postsRef = ref.child("posts");

DatabaseReference newPostRef = postsRef.push();
newPostRef.setValueAsync(new Post("gracehop", "Announcing COBOL, a New Programming Language"));

// We can also chain the two calls together
postsRef.push().setValueAsync(new Post("alanisawesome", "The Turing Machine"));
Node.js
const newPostRef = postsRef.push();
newPostRef.set({
  author: 'gracehop',
  title: 'Announcing COBOL, a New Programming Language'
});

// we can also chain the two calls together
postsRef.push().set({
  author: 'alanisawesome',
  title: 'The Turing Machine'
});
Python
posts_ref = ref.child('posts')

new_post_ref = posts_ref.push()
new_post_ref.set({
    'author': 'gracehop',
    'title': 'Announcing COBOL, a New Programming Language'
})

# We can also chain the two calls together
posts_ref.push().set({
    'author': 'alanisawesome',
    'title': 'The Turing Machine'
})
ไป

// Post is a json-serializable type.
type Post struct {
	Author string `json:"author,omitempty"`
	Title  string `json:"title,omitempty"`
}

postsRef := ref.Child("posts")

newPostRef, err := postsRef.Push(ctx, nil)
if err != nil {
	log.Fatalln("Error pushing child node:", err)
}

if err := newPostRef.Set(ctx, &Post{
	Author: "gracehop",
	Title:  "Announcing COBOL, a New Programming Language",
}); err != nil {
	log.Fatalln("Error setting value:", err)
}

// We can also chain the two calls together
if _, err := postsRef.Push(ctx, &Post{
	Author: "alanisawesome",
	Title:  "The Turing Machine",
}); err != nil {
	log.Fatalln("Error pushing child node:", err)
}

คีย์เฉพาะจะขึ้นอยู่กับการประทับเวลา ดังนั้นรายการในรายการจะถูกจัดเรียงตามลำดับเวลาโดยอัตโนมัติ เนื่องจาก Firebase สร้างคีย์ที่ไม่ซ้ำกันสำหรับโพสต์บล็อกแต่ละรายการ จะไม่มีข้อขัดแย้งในการเขียนเกิดขึ้นหากผู้ใช้หลายคนเพิ่มโพสต์พร้อมกัน ข้อมูลฐานข้อมูลของคุณตอนนี้มีลักษณะดังนี้:

{
  "posts": {
    "-JRHTHaIs-jNPLXOQivY": {
      "author": "gracehop",
      "title": "Announcing COBOL, a New Programming Language"
    },
    "-JRHTHaKuITFIhnj02kE": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

ใน JavaScript, Python และไปที่รูปแบบของการเรียก push() และจากนั้นทันทีเรียก set() เป็นเพื่อร่วมกันว่า Firebase SDK ช่วยให้คุณสามารถรวมพวกเขาโดยการส่งผ่านข้อมูลที่จะตั้งโดยตรงกับ push() ดังต่อไปนี้:

Java
// No Java equivalent
Node.js
// This is equivalent to the calls to push().set(...) above
postsRef.push({
  author: 'gracehop',
  title: 'Announcing COBOL, a New Programming Language'
});;
Python
# This is equivalent to the calls to push().set(...) above
posts_ref.push({
    'author': 'gracehop',
    'title': 'Announcing COBOL, a New Programming Language'
})
ไป
if _, err := postsRef.Push(ctx, &Post{
	Author: "gracehop",
	Title:  "Announcing COBOL, a New Programming Language",
}); err != nil {
	log.Fatalln("Error pushing child node:", err)
}

รับคีย์เฉพาะที่สร้างโดย push()

โทร push() จะกลับอ้างอิงถึงข้อมูลเส้นทางใหม่ซึ่งคุณสามารถใช้เพื่อรับคีย์หรือชุดข้อมูลไป รหัสต่อไปนี้จะส่งผลให้มีข้อมูลเดียวกันกับตัวอย่างข้างต้น แต่ตอนนี้ เราจะสามารถเข้าถึงคีย์เฉพาะที่สร้างขึ้นได้:

Java
// Generate a reference to a new location and add some data using push()
DatabaseReference pushedPostRef = postsRef.push();

// Get the unique ID generated by a push()
String postId = pushedPostRef.getKey();
Node.js
// Generate a reference to a new location and add some data using push()
const newPostRef = postsRef.push();

// Get the unique key generated by push()
const postId = newPostRef.key;
Python
# Generate a reference to a new location and add some data using push()
new_post_ref = posts_ref.push()

# Get the unique key generated by push()
post_id = new_post_ref.key
ไป
// Generate a reference to a new location and add some data using Push()
newPostRef, err := postsRef.Push(ctx, nil)
if err != nil {
	log.Fatalln("Error pushing child node:", err)
}

// Get the unique key generated by Push()
postID := newPostRef.Key

ที่คุณสามารถดูคุณจะได้รับค่าของคีย์ที่ไม่ซ้ำกันจาก push() อ้างอิง

ในส่วนถัดไปใน การดึงข้อมูล ที่เราจะได้เรียนรู้วิธีการอ่านข้อมูลจากฐานข้อมูล Firebase

การบันทึกข้อมูลธุรกรรม

เมื่อทำงานร่วมกับข้อมูลที่ซับซ้อนที่อาจได้รับความเสียหายจากการปรับเปลี่ยนพร้อมกันเช่นเคาน์เตอร์เพิ่มขึ้น SDK ให้ การดำเนินการทำธุรกรรม

ใน Java และ Node.js คุณให้การเรียกกลับสองครั้งแก่การดำเนินการธุรกรรม: ฟังก์ชันการอัพเดตและการเรียกกลับการเสร็จสิ้นที่เป็นทางเลือก ใน Python และ Go การดำเนินการธุรกรรมถูกบล็อก ดังนั้นจึงยอมรับเฉพาะฟังก์ชันการอัพเดทเท่านั้น

ฟังก์ชันอัปเดตใช้สถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์ และควรส่งคืนสถานะใหม่ที่คุณต้องการจะเขียน ตัวอย่างเช่น หากคุณต้องการเพิ่มจำนวน upvotes ในบล็อกโพสต์เฉพาะ คุณจะต้องเขียนธุรกรรมดังต่อไปนี้:

Java
DatabaseReference upvotesRef = ref.child("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes");
upvotesRef.runTransaction(new Transaction.Handler() {
  @Override
  public Transaction.Result doTransaction(MutableData mutableData) {
    Integer currentValue = mutableData.getValue(Integer.class);
    if (currentValue == null) {
      mutableData.setValue(1);
    } else {
      mutableData.setValue(currentValue + 1);
    }

    return Transaction.success(mutableData);
  }

  @Override
  public void onComplete(
      DatabaseError databaseError, boolean committed, DataSnapshot dataSnapshot) {
    System.out.println("Transaction completed");
  }
});
Node.js
const upvotesRef = db.ref('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction((current_value) => {
  return (current_value || 0) + 1;
});
Python
def increment_votes(current_value):
    return current_value + 1 if current_value else 1

upvotes_ref = db.reference('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes')
try:
    new_vote_count = upvotes_ref.transaction(increment_votes)
    print('Transaction completed')
except db.TransactionAbortedError:
    print('Transaction failed to commit')
ไป
fn := func(t db.TransactionNode) (interface{}, error) {
	var currentValue int
	if err := t.Unmarshal(&currentValue); err != nil {
		return nil, err
	}
	return currentValue + 1, nil
}

ref := client.NewRef("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes")
if err := ref.Transaction(ctx, fn); err != nil {
	log.Fatalln("Transaction failed to commit:", err)
}

ตรวจสอบตัวอย่างข้างต้นเพื่อดูว่านับเป็น null หรือไม่ได้รับการเพิ่มขึ้นเลยตั้งแต่การทำธุรกรรมสามารถเรียกว่ามี null ถ้าค่าเริ่มต้นไม่ถูกเขียน

หากโค้ดข้างต้นได้รับการทำงานโดยไม่ต้องฟังก์ชั่นการทำธุรกรรมและสองลูกค้าพยายามที่จะเพิ่มขึ้นพร้อมกันพวกเขาทั้งสองจะเขียน 1 เป็นค่าใหม่ส่งผลในการเพิ่มขึ้นแทนของทั้งสอง

การเชื่อมต่อเครือข่ายและการเขียนแบบออฟไลน์

Firebase Node.js และไคลเอ็นต์ Java จะรักษาเวอร์ชันภายในของข้อมูลที่ใช้งานอยู่ เมื่อเขียนข้อมูลแล้ว ข้อมูลนั้นจะถูกเขียนลงในเวอร์ชันภายในเครื่องก่อน จากนั้นไคลเอ็นต์จะซิงโครไนซ์ข้อมูลนั้นกับฐานข้อมูลและกับไคลเอ็นต์อื่นๆ ด้วย "ความพยายามอย่างดีที่สุด"

ด้วยเหตุนี้ การเขียนทั้งหมดไปยังฐานข้อมูลจะทริกเกอร์เหตุการณ์ในเครื่องทันที ก่อนที่ข้อมูลใดๆ จะถูกเขียนลงในฐานข้อมูลด้วยซ้ำ ซึ่งหมายความว่าเมื่อคุณเขียนโปรแกรมประยุกต์ใช้ Firebase ให้แอปของคุณจะยังคงตอบสนองโดยไม่คำนึงถึงแฝงเครือข่ายหรือการเชื่อมต่ออินเทอร์เน็ต

เมื่อการเชื่อมต่อถูกสร้างขึ้นใหม่ เราจะได้รับชุดเหตุการณ์ที่เหมาะสม เพื่อให้ไคลเอ็นต์ "ทัน" กับสถานะเซิร์ฟเวอร์ปัจจุบัน โดยไม่ต้องเขียนโค้ดที่กำหนดเองใดๆ

การรักษาความปลอดภัยข้อมูลของคุณ

ฐานข้อมูลเรียลไทม์ของ Firebase มีภาษาความปลอดภัยที่ช่วยให้คุณกำหนดได้ว่าผู้ใช้รายใดมีสิทธิ์เข้าถึงแบบอ่านและเขียนไปยังโหนดต่างๆ ของข้อมูลของคุณ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับมันใน การรักษาความปลอดภัยข้อมูลของคุณ