Giới thiệu về SQLite trong Android
SQLite là một cơ sở dữ liệu SQL mã nguồn mở, lưu trữ dữ liệu vào tệp văn bản trên thiết bị. Android tích hợp sẵn SQLite, hỗ trợ đầy đủ các tính năng của cơ sở dữ liệu quan hệ. Để truy cập cơ sở dữ liệu này, bạn không cần thiết lập kết nối như JDBC hay ODBC.
Ví dụ: Sử dụng ràng buộc UNIQUE để đảm bảo dữ liệu không trùng lặp
Hướng dẫn này minh họa cách định nghĩa ràng buộc UNIQUE trên cột khi tạo bảng, ngăn chặn việc chèn dữ liệu trùng lặp.
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Thiết kế giao diện (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">
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:hint="Nhập tên"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/salary"
android:layout_width="match_parent"
android:inputType="numberDecimal"
android:hint="Nhập lương"
android:layout_height="wrap_content" />
<Button
android:id="@+id/save"
android:text="Lưu"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Bước 3: Code MainActivity.java
package com.example.andy.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
Button save;
EditText name, salary;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final DatabaseHelper helper = new DatabaseHelper(this);
name = findViewById(R.id.name);
salary = findViewById(R.id.salary);
findViewById(R.id.save).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String nameStr = name.getText().toString().trim();
String salaryStr = salary.getText().toString().trim();
if (!nameStr.isEmpty() && !salaryStr.isEmpty()) {
if (helper.insert(nameStr, salaryStr)) {
Toast.makeText(MainActivity.this, "Đã thêm", Toast.LENGTH_LONG).show();
name.setText("");
salary.setText("");
} else {
Toast.makeText(MainActivity.this, "Không thêm được (có thể trùng UNIQUE)", Toast.LENGTH_LONG).show();
}
} else {
name.setError("Nhập TÊN");
salary.setError("Nhập LƯƠNG");
}
}
});
}
}
Bước 4: Code DatabaseHelper.java (có UNIQUE constraint)
package com.example.andy.myapplication;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "MyDBName";
public static final String CONTACTS_TABLE_NAME = "SalaryDetails";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
// Quan trọng: UNIQUE trên cột id và name
db.execSQL("create table " + CONTACTS_TABLE_NAME +
"(id integer primary key NOT NULL UNIQUE, " +
" name text NOT NULL UNIQUE, " +
" salary text NOT NULL)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + CONTACTS_TABLE_NAME);
onCreate(db);
}
public boolean insert(String name, String salary) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name", name);
contentValues.put("salary", salary);
try {
long result = db.insertOrThrow(CONTACTS_TABLE_NAME, null, contentValues);
return result != -1;
} catch (android.database.sqlite.SQLiteConstraintException e) {
// Vi phạm UNIQUE constraint
e.printStackTrace();
return false;
}
}
}
Chạy ứng dụng
Kết nối thiết bị Android thật với máy tính. Trong Android Studio, mở file activity và nhấn biểu tượng Run. Chọn thiết bị di động và kiểm tra màn hình hiển thị.

Nhập giá trị và nhấn Lưu:

Kiểm tra dữ liệu trong Database Inspector:

Giải thích ràng buộc UNIQUE
- UNIQUE: Đảm bảo tất cả giá trị trong cột (hoặc nhóm cột) là duy nhất, không trùng lặp
- PRIMARY KEY ngầm hiểu là
NOT NULL UNIQUE - Có thể áp dụng cho một cột hoặc nhóm cột (composite unique)
- Vi phạm UNIQUE → ném
SQLiteConstraintException(subclass của SQLException)
Các cách định nghĩa UNIQUE
-- 1. Cột đơn lẻ (inline)
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
username TEXT UNIQUE
);
-- 2. Nhóm cột (composite unique) - ở cuối bảng
CREATE TABLE enrollments (
student_id INTEGER,
course_id INTEGER,
semester TEXT,
UNIQUE(student_id, course_id, semester) -- 1 sinh viên chỉ đăng ký 1 môn/học kỳ
);
-- 3. Đặt tên constraint (dễ quản lý, drop sau này)
CREATE TABLE products (
id INTEGER PRIMARY KEY,
sku TEXT,
barcode TEXT,
CONSTRAINT uq_product_sku UNIQUE (sku),
CONSTRAINT uq_product_barcode UNIQUE (barcode)
);
Xử lý vi phạm UNIQUE trong Android
public boolean insertUser(String email, String name) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("email", email);
cv.put("name", name);
try {
// insertOrThrow ném exception nếu vi phạm constraint
long id = db.insertOrThrow("users", null, cv);
return id != -1;
} catch (SQLiteConstraintException e) {
// Xử lý trùng lặp: log, trả về false, hoặc update thay vì insert
Log.w("DB", "Email đã tồn tại: " + email);
return false;
}
}
// Hoặc dùng INSERT OR IGNORE / INSERT OR REPLACE
// INSERT OR IGNORE: bỏ qua nếu trùng, không báo lỗi
// INSERT OR REPLACE: xóa bản ghi cũ, chèn mới (cần PRIMARY KEY hoặc UNIQUE)
db.execSQL("INSERT OR IGNORE INTO users (email, name) VALUES (?, ?)", new Object[]{email, name});
UNIQUE vs INDEX
| Đặc điểm | UNIQUE | INDEX (CREATE INDEX) |
|---|---|---|
| Đảm bảo duy nhất | Có | Không |
| Tăng tốc truy vấn | Có (tự tạo index) | Có |
| Cho phép NULL | Có (nhiều NULL được phép)* | Có |
| Dùng cho | Email, username, SKU... | Cột thường WHERE/JOIN |
* SQLite cho phép nhiều NULL trong cột UNIQUE (theo chuẩn SQL). Muốn chỉ 1 NULL: thêm NOT NULL.
Best Practice
- Luôn bắt exception
SQLiteConstraintExceptionkhi insert/update có UNIQUE - Dùng
INSERT OR REPLACEcho upsert (update nếu tồn tại, insert nếu không) - Đặt tên constraint rõ ràng:
CONSTRAINT uq_table_column UNIQUE (column) - Kết hợp
NOT NULL UNIQUEcho các trường bắt buộc duy nhất (email, phone)