Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ total_changes() ใน SQLite บน Android

การใช้ฟังก์ชัน total_changes() ใน SQLite บน Android

ฟังก์ชัน total_changes() ใน SQLite คืนค่าจำนวนแถวที่ถูกเปลี่ยนแปลง (INSERT, UPDATE, DELETE) ตั้งแต่การเชื่อมต่อฐานข้อมูลเปิดจนถึงปัจจุบัน ใช้สำหรับติดตามการเปลี่ยนแปลงข้อมูลสะสม

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

สร้างโปรเจกต์ Android ใหม่ใน Android Studio

ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ป้อนชื่อ" />

    <EditText
        android:id="@+id/etSalary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ป้อนเงินเดือน"
        android:inputType="numberDecimal" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">
        <Button android:id="@+id/btnSave" android:text="บันทึก" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnRefresh" android:text="รีเฟรช" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnUpdate" android:text="อัปเดต" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnDelete" android:text="ลบทั้งหมด" android:layout_width="wrap_content" android:layout_height="wrap_content" />
    </LinearLayout>

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp">
    </ListView>
</LinearLayout>

ขั้นตอนที่ 3: MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private EditText etName, etSalary;
    private ListView listView;
    private ArrayAdapter<String> adapter;
    private DatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dbHelper = new DatabaseHelper(this);
        ArrayList<String> dataList = dbHelper.getTotalChanges();

        etName = findViewById(R.id.etName);
        etSalary = findViewById(R.id.etSalary);
        listView = findViewById(R.id.listView);

        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);
        listView.setAdapter(adapter);

        findViewById(R.id.btnDelete).setOnClickListener(v -> {
            Toast.makeText(this, dbHelper.deleteAll() ? "ลบสำเร็จ" : "ลบไม่สำเร็จ", Toast.LENGTH_LONG).show();
        });

        findViewById(R.id.btnUpdate).setOnClickListener(v -> {
            String name = etName.getText().toString().trim();
            String salary = etSalary.getText().toString().trim();
            if (!name.isEmpty() && !salary.isEmpty()) {
                Toast.makeText(this, dbHelper.update(name, salary) ? "อัปเดตสำเร็จ" : "อัปเดตไม่สำเร็จ", Toast.LENGTH_LONG).show();
            } else {
                etName.setError("กรุณาป้อนชื่อ");
                etSalary.setError("กรุณาป้อนเงินเดือน");
            }
        });

        findViewById(R.id.btnRefresh).setOnClickListener(v -> {
            dataList.clear();
            dataList.addAll(dbHelper.getTotalChanges());
            adapter.notifyDataSetChanged();
        });

        findViewById(R.id.btnSave).setOnClickListener(v -> {
            String name = etName.getText().toString().trim();
            String salary = etSalary.getText().toString().trim();
            if (!name.isEmpty() && !salary.isEmpty()) {
                Toast.makeText(this, dbHelper.insert(name, salary) ? "บันทึกสำเร็จ" : "บันทึกไม่สำเร็จ", Toast.LENGTH_LONG).show();
            } else {
                etName.setError("กรุณาป้อนชื่อ");
                etSalary.setError("กรุณาป้อนเงินเดือน");
            }
        });
    }
}

ขั้นตอนที่ 4: DatabaseHelper.java - ใช้ total_changes() ใน Query

package com.example.myapplication;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "salaryDatabase";
    private static final String TABLE_NAME = "SalaryDetails";
    private static final int DB_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                     "name TEXT, salary REAL, datetime DEFAULT CURRENT_TIMESTAMP)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    public boolean insert(String name, String salary) {
        SQLiteDatabase db = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("salary", salary);
        return db.insert(TABLE_NAME, null, values) != -1;
    }

    // จุดสำคัญ: Query total_changes() - แสดงจำนวนการเปลี่ยนแปลงสะสม
    public ArrayList<String> getTotalChanges() {
        SQLiteDatabase db = getReadableDatabase();
        ArrayList<String> list = new ArrayList<>();
        // total_changes() คืนค่าจำนวน row ที่เปลี่ยนแปลงตั้งแต่เปิด connection
        Cursor cursor = db.rawQuery("SELECT total_changes() as total_changes", null);

        if (cursor.moveToFirst()) {
            do {
                list.add("Total changes since DB opened: " + cursor.getInt(0));
            } while (cursor.moveToNext());
        }
        cursor.close();
        return list;
    }

    public boolean update(String name, String salary) {
        SQLiteDatabase db = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("salary", salary);
        return db.update(TABLE_NAME, values, "name = ?", new String[]{name}) > 0;
    }

    public boolean deleteAll() {
        return getWritableDatabase().delete(TABLE_NAME, null, null) > 0;
    }
}

คำอธิบาย total_changes()

  • total_changes() คืนค่าจำนวนแถวที่ถูก INSERT, UPDATE, DELETE สะสมตั้งแต่เปิด database connection
  • ต่างจาก changes() ที่คืนค่าเฉพาะ statement ล่าสุดเท่านั้น
  • นับเฉพาะการเปลี่ยนแปลงผ่าน SQL statement โดยตรง (ไม่นับ cascade จาก foreign key)
  • ค่าจะรีเซ็ตเมื่อปิด database connection (new SQLiteOpenHelper instance)

ตัวอย่างการทำงาน

  1. เปิดแอป (connection ใหม่) → total_changes() = 0
  2. INSERT 3 records → total_changes() = 3
  3. UPDATE 1 record → total_changes() = 4
  4. DELETE 2 records → total_changes() = 6
  5. ปิดแอปเปิดใหม่ → total_changes() = 0 (reset)

ความแตกต่างระหว่าง changes() และ total_changes()

ฟังก์ชันขอบเขตReset เมื่อ
changes()Statement ล่าสุดเท่านั้นStatement ถัดไป
total_changes()สะสมตั้งแต่เปิด connectionปิด connection

การใช้งานจริง

  • Audit logging: ติดตามจำนวนการเปลี่ยนแปลงข้อมูล
  • Undo/Redo: ตรวจสอบว่ามีการเปลี่ยนแปลงหรือไม่
  • Sync: ตรวจสอบว่ามีข้อมูลใหม่ต้อง sync หรือไม่
  • Debugging: ตรวจสอบว่าคำสั่ง SQL ทำงานถูกต้อง

หมายเหตุ

ใน Android SQLiteOpenHelper จะจัดการ connection ให้อัตโนมัติ การเรียก getWritableDatabase() หรือ getReadableDatabase() อาจ reuse connection เดียวกัน ดังนั้น total_changes() จะสะสมตลอดอายุของแอป (จนกว่าจะ process ถูก kill)