iT邦幫忙

2024 iThome 鐵人賽

DAY 27
1
佛心分享-SideProject30

未來IT將來系列 第 27

未來IT將來2024.27「App內建關聯式資料庫管理系統」實作

  • 分享至 

  • xImage
  •  

一、引言

在現代應用程式開發中,數據管理是不可或缺的部分。無論是行動應用、桌面應用,還是網頁應用,數據的存儲、檢索與管理都是核心功能之一。關聯式資料庫管理系統(RDBMS)以其結構化的數據存儲方式和強大的查詢能力,成為眾多應用的首選。隨著App技術的進步,如何在行動應用中內建高效的關聯式資料庫管理系統,並優化其性能,成為開發者面臨的主要挑戰之一。
本文將探討如何在行動應用中實作內建的關聯式資料庫管理系統,並介紹相關的開發技術和工具。

二、關聯式資料庫管理系統概述

  1. RDBMS的基礎概念
    關聯式資料庫管理系統是一種基於關聯模型的資料庫管理系統,通過行和列的方式存儲數據。每個表格(table)由若干列(column)和行(row)構成,列代表數據的屬性,行代表具體的數據記錄。關聯式資料庫支持SQL(結構化查詢語言)進行數據查詢、插入、更新和刪除等操作。
  2. 常見的內建資料庫解決方案
    在行動應用中,常見的內建資料庫解決方案包括:
    • SQLite:輕量級的嵌入式關聯式資料庫,適用於小型應用,無需單獨的伺服器管理。
    • Room:Google推出的SQLite ORM(物件關聯映射)框架,簡化了在Android應用中使用SQLite的操作。
    • Core Data:蘋果提供的資料管理框架,適用於iOS和macOS應用,支持關聯數據、圖像數據和文件的存儲。
    • Realm:一種新型的移動資料庫,支持線上和離線數據同步,性能優於SQLite。

三、App內建關聯式資料庫的實作步驟

  1. 選擇合適的資料庫
    在選擇內建的資料庫管理系統時,需要根據應用的需求來決定。SQLite是最常見的選擇,其輕量級特性和良好的性能使其成為多數行動應用的首選。對於更複雜的需求,Room或Realm可能更適合。
  2. 設計資料庫架構
    在實作資料庫之前,首先需要設計好資料庫的架構,包括表格的結構、數據的關聯性以及各種索引的設置。這將直接影響資料庫的性能和可維護性。
    sql程式碼
CREATE TABLE Users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL
);

CREATE TABLE Orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    product_name TEXT NOT NULL,
    quantity INTEGER NOT NULL,
    FOREIGN KEY (user_id) REFERENCES Users(id)
);
  1. 在App中實作SQLite
    以Android應用為例,可以使用原生的SQLite API來管理資料庫,也可以使用Room來簡化操作。

SQLite示例:java程式碼

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "app_database.db";
    private static final int DATABASE_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String createUserTable = "CREATE TABLE Users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT)";
        db.execSQL(createUserTable);
    }

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

Room示例:java程式碼

@Entity
public class User {
    @PrimaryKey(autoGenerate = true)
    public int id;
    public String name;
    public String email;
}

@Dao
public interface UserDao {
    @Insert
    void insertUser(User user);

    @Query("SELECT * FROM User WHERE id = :id")
    User getUserById(int id);
}

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}
  1. 資料操作與優化
    在使用內建資料庫時,開發者需要關注數據操作的效率。以下是一些常見的優化策略:
    • 索引:在查詢頻繁的列上建立索引,可以顯著提高查詢速度。
    • 批量操作:儘量使用批量插入、更新操作,減少與資料庫的交互次數。
    • 異步操作:在主線程以外的線程中進行資料庫操作,避免阻塞UI。
  2. 測試與除錯
    實作完成後,對資料庫進行全面的測試,包括資料插入、查詢、更新、刪除等操作的測試。此外,還應檢查資料庫性能,確保其能夠應對大數據量操作。

四、應用案例

  1. 電子商務應用
    在電子商務應用中,內建的關聯式資料庫可以用來管理用戶信息、產品目錄、訂單記錄等。通過合理的資料庫設計,可以確保系統在處理大量訂單時保持高效。
  2. 個人理財應用
    個人理財應用需要管理用戶的收入、支出、投資等財務數據。內建的關聯式資料庫可以有效地組織這些數據,並提供快速的查詢和統計分析功能。
  3. 內容管理系統
    內容管理系統(CMS)需要處理大量的文章、圖片、音頻、視頻等內容。通過內建資料庫,系統可以實現內容的高效存儲與檢索,並支持離線模式。

五、結語

內建關聯式資料庫管理系統是行動應用開發中的關鍵組成部分。通過選擇適當的資料庫技術,並根據應用需求進行優化,可以顯著提高應用的性能和用戶體驗。隨著資料庫技術的不斷進步,未來的行動應用將在數據管理方面擁有更強的能力。

附件.以B4A實作內建關聯式資料庫行動應用App

Sub Process_Globals
	Public SQL1 As SQL
	
	Public CurrentIndex = -1 As Int		' index of the current entry
	
	Public RowIDList As List		' list containing the RowIDs of the database
	' we need it because the IDs can be different from the list indexes
	' if we delete an entry its ID is lost
End Sub

Sub Globals
	Private lblRowID As Label
	Private edtFirstName, edtLastName, edtCity As EditText
End Sub

Sub Activity_Create(FirstTime As Boolean)
	'**** opreating system specific code
	Activity.LoadLayout("Main")
	Activity.Title = "SQLiteLight1"
	
	'**** program specific code
	If FirstTime Then
		' File.Delete(File.DirInternal, "persons.db") ' for testing, removes the database
		
		'check if the database already exists
		If File.Exists(File.DirInternal, "persons.db") = False Then
			'if not, initialize it 
			SQL1.Initialize(File.DirInternal, "persons.db", True)
			'and create it
			CreateDataBase
		Else
			'if yes, initialize it
			SQL1.Initialize(File.DirInternal, "persons.db", True)
		End If
	End If
End Sub

Sub Activity_Resume
	RowIDList.Initialize		'initialize the rowID list
	ReadDataBase						'read the database
	ShowEntry(0)						'show the first entry
End Sub

Sub Activity_Pause (UserClosed As Boolean)
	If UserClosed Then
		SQL1.Close		'if the user closes the program we close the database
	End If
End Sub

Private Sub CreateDataBase
	Private Query As String
	
	'create the database with 3 columns
	Query = "CREATE TABLE persons (FirstName TEXT, LastName TEXT, City TEXT)"
	SQL1.ExecNonQuery(Query)

	'Fill a few entries
	Query = "INSERT INTO persons VALUES (?, ?, ?)"
	SQL1.ExecNonQuery2(Query, Array As Object("John", "KENNEDY", "New York"))
	SQL1.ExecNonQuery2(Query, Array As Object("Peter", "FALK", "Los Angeles"))
	SQL1.ExecNonQuery2(Query, Array As Object("Jack", "LONDON", "Seattle"))
	SQL1.ExecNonQuery2(Query, Array As Object("Ronald", "REGAN", "Los Angeles"))
End Sub

Private Sub ReadDataBase
	Private ResultSet1 As ResultSet
	
	RowIDList.Clear									'initialize the RowID list
	'We read only the internal 'rowid' column and put the rowids in a List
	ResultSet1 = SQL1.ExecQuery("SELECT rowid FROM persons")
	Do While ResultSet1.NextRow
		RowIDList.Add(ResultSet1.GetInt2(0))		'add the rowid's to the RowID list
	Loop
	CurrentIndex = 0			'set the current index to 0
	ResultSet1.Close			'close the ResultSet, we don't need it anymore
End Sub

Private Sub ShowEntry(EntryIndex As Int)
	Private ResultSet1 As ResultSet
	Private RowID As Int
	
	If RowIDList.Size = 0 Then 		'check if the database is empty
		Return											'if yes leave the routine
	End If
	
	RowID = RowIDList.Get(EntryIndex)		'get the RowID for the given entry index
	'read the entry with the given RowID
	ResultSet1 = SQL1.ExecQuery("SELECT * FROM persons WHERE rowid = " & RowID)
	lblRowID.Text = RowID																	'display the RowID
	ResultSet1.NextRow																		'set the next row
	edtFirstName.Text = ResultSet1.GetString("FirstName")	'read the FirstName column
	edtLastName.Text = ResultSet1.GetString("LastName")		'read the LasstName column
	edtCity.Text = ResultSet1.GetString("City")						'read  the City column
	ResultSet1.Close										'close the ResultSet, we don't it anymore
End Sub

Private Sub AddEntry
	Private Query As String
	Private ResultSet1 As ResultSet
	Private RowID As Int

	'we check if all fields are filled
	If edtFirstName.Text = "" Or edtLastName.Text = "" Or edtCity.Text = "" Then
		Msgbox("One or more data is missing", "Missing data")
		Return
	End If
	
	'we check if an entry with the same name already exists
	Query = "SELECT * FROM persons WHERE FirstName = ? AND LastName = ? AND City = ?"
	ResultSet1 = SQL1.ExecQuery2(Query, Array As String (edtFirstName.Text, edtLastName.Text, edtCity.Text))

	If ResultSet1.NextRow = True Then
		'if it exists show a message and do nothing else
		ToastMessageShow("This entry already exists", False)
	Else
		'if not, add the entry
		'we use ExecNonQuery2 because it's easier, we don't need to take care of the data types 
		Query = "INSERT INTO persons VALUES (?, ?, ?)"
		SQL1.ExecNonQuery2(Query, Array As String(edtFirstName.Text, edtLastName.Text, edtCity.Text))
		
		ToastMessageShow("Entry added", False)	' confirmation message for the user
		
		'to display the rowid of the last entry we read the max value of the internal 'rowid' column 
		RowID = SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM persons")
		RowIDList.Add(RowID)								'add the last rowid to the list
		CurrentIndex = RowIDList.Size - 1		'set the current index to the last one
		lblRowID.Text = RowID								'display the last index
	End If
	ResultSet1.Close											'close the ResultSet, we don't it anymore
End Sub

Private Sub DeleteEntry
	Private Query As String
	Private Answ As Int
	
	'ask the user for confirmation
	Answ = Msgbox2("Do you really want to delete " & edtFirstName.Text & " " & edtLastName.Text, "Delete entry", "Yes", "", "No", Null)

	If Answ = DialogResponse.POSITIVE Then			'if yes, delete the entry
		Query = "DELETE FROM persons WHERE rowid = " & RowIDList.Get(CurrentIndex)
		SQL1.ExecNonQuery(Query)									'delete the entry
		RowIDList.RemoveAt(CurrentIndex)					'remove the rowid from the list
		If CurrentIndex = RowIDList.Size Then			'if the current index is the last one
			CurrentIndex = CurrentIndex - 1					'decrement it by 1
		End If
		ShowEntry(CurrentIndex)										'show the next entry
		ToastMessageShow("Entry deleted", False)	'confirmation for the user
	End If
End Sub

Private Sub UpdateEntry
	Private Query As String
	
	Query = "UPDATE persons Set FirstName = ?, LastName = ?, City = ? WHERE rowid = " & RowIDList.Get(CurrentIndex)
	SQL1.ExecNonQuery2(Query, Array As String(edtFirstName.Text, edtLastName.Text, edtCity.Text))
	ToastMessageShow("Entry updated", False)		'display a confirmation message
End Sub

參考網址
• B4X SQLite Database https://www.b4x.com/guides/B4XSQLiteDatabase.html
• SQLite 官方網站(https://www.sqlite.org/)
• Android Room 官方文檔(https://developer.android.com/training/data-storage/room?hl=zh-tw)
• Realm 官方網站(https://www.mongodb.com/zh-cn/docs/atlas/device-sdks/)
• Core Data 蘋果官方文檔(https://developer.apple.com/documentation/coredata)


上一篇
未來IT將來2024.26「區塊鏈(Blockchain)實作」
下一篇
未來IT將來2024.28「OpenData+JSON」實作
系列文
未來IT將來31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言