1、 引言

Android 中的 SQLite 是一种轻量级、嵌入式的关系型数据库,专为资源受限的设备(如智能手机和平板)设计。它被深度集成在 Android 系统中,是官方推荐用于本地结构化数据持久化的方案之一。

2、 核心特点

  • 无服务端架构:SQLite 不需要独立的数据库服务器,数据库以单个 .db 文件形式存储在应用私有目录中。

  • 轻量高效:内存占用仅数百 KB,适合移动设备。

  • 标准 SQL 支持:支持大部分 SQL 语法(如 SELECT, INSERT, UPDATE, DELETE, CREATE TABLE 等)。

  • 数据类型灵活:支持 NULL(空值)、INTEGER(整数)、REAL(浮点数)、TEXT(字符串)、BLOB(大数据),且具备动态类型系统和隐式类型转换。

  • 安全隔离:数据库文件默认存储在 /data/data/<包名>/databases/ 下,其他应用无法直接访问(除非 root )。

3、Android 操作 SQLite 的核心类

在 Android 开发中使用 SQLite 数据库,有三个核心类是我们需要深入了解和熟练掌握的,它们分别是 SQLiteOpenHelper、SQLiteDatabase和 Cursor。这三个类在 SQLite 数据库的操作过程中各自有着独特的作用和使用场景。

  1. SQLiteOpenHelper:是一个非常重要的辅助类,它主要负责管理数据库的创建和版本更新。当我们的应用需要创建一个 SQLite 数据库时,通常会创建一个类继承自 SQLiteOpenHelper,并在这个类中重写 onCreate 和 onUpgrade 方法。onCreate 方法在数据库首次创建时被调用,我们可以在这个方法中编写创建数据库表结构的 SQL 语句。而 onUpgrade 方法则在数据库版本发生变化时被调用,比如我们需要添加新的表字段、修改表结构或者删除旧表时,就可以在这个方法中实现相应的逻辑。

  2. SQLiteDatabase:是操作 SQLite 数据库的核心类,它就像是一个万能的数据库操作工具,封装了大量用于操作数据库的 API。通过这些 API,我们可以轻松地对数据库进行各种操作,比如执行 SQL 语句(无论是简单的查询、插入,还是复杂的创建表、删除表等操作)。它提供了如 insert、delete、update、query 等方法,这些方法使得我们能够方便地进行数据的增、删、改、查操作。

  3. Cursor:是用于遍历查询结果集的工具。当我们执行一个查询操作(如使用 SQLiteDatabase 的 query 或 rawQuery 方法)后,会返回一个 Cursor 对象,这个对象就像是一个指向查询结果集的游标。我们可以通过它提供的一系列方法(如 moveToFirst、moveToNext、getInt、getString 等)来逐行读取和获取结果集中的数据。务必在使用后关闭,避免内存泄漏。

4、创建数据库和表

在 Android 中创建 SQLite 数据库,通常的做法是创建一个类继承自 SQLiteOpenHelper 类,然后重写其中的 onCreate 和 onUpgrade 方法。这两个方法在数据库的创建和版本管理过程中起着至关重要的作用。

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "APPLogs.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 CREATE_TABLE = "CREATE TABLE logs (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "http_status INTEGER," +
                "create_time TEXT NOT NULL)";
        db.execSQL(CREATE_TABLE);
    }
    
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 当数据库版本发生变化时,先删除旧表,再重新创建新表
        db.execSQL("DROP TABLE IF EXISTS logs");
        onCreate(db);
    }
}

5、基本操作

在创建好数据库和表之后,我们就需要对其中的数据进行各种操作,最常见的就是增(Create)、查(Read)、改(Update)、删(Delete)操作,简称 CRUD 操作。

  • 插入数据

在 Android 中,向 SQLite 数据库插入数据有两种常见的方式,一种是使用 insert 方法,另一种是使用 execSQL 方法。

// 方法1:使用ContentValues
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("id", 1);
values.put("http_status", 2);
values.put("create_time", "2026-01-01");
//把数据插入到数据库中,返回当前行的id,若为-1则数据插入失败
long newRowId = db.insert("logs", null, values);

// 方法2:使用execSQL
db.execSQL("INSERT INTO logs (id, http_status, create_time) VALUES (?, ?, ?)",
 new Object[]{0, 1, "2026-01-01"});
  • 查询数据

在 SQLite 数据库中查询数据,我们主要使用 query 和 rawQuery 方法。这两个方法都用于执行查询操作,但在使用方式上略有不同。

query 方法是一种较为便捷的查询方式,它的参数较多,可以通过这些参数来指定查询的表名、要查询的列、查询条件、条件参数、分组方式、过滤条件和排序方式等。

rawQuery 方法则更加灵活,它允许我们直接编写 SQL 查询语句。方法的第一个参数是 SQL 查询语句,第二个参数是查询条件的参数数组(如果没有条件参数,可以设为 null)。这种方式适用于一些复杂的查询场景,比如多表联合查询等。

无论是使用 query 方法还是 rawQuery 方法,在查询操作完成后,都要记得关闭 Cursor 和数据库连接,以释放资源,避免内存泄漏。

// 方法1:使用query()方法
SQLiteDatabase db = dbHelper.getReadableDatabase();
// query参数依次为:表名、要查询的列、WHERE条件、WHERE参数、GROUP BY、HAVING、ORDER BY
Cursor cursor = db.query("logs", null, null,null, null, null, null);
try {
    while (cursor.moveToNext()) {
        int id = cursor.getInt(cursor.getColumnIndexOrThrow("id"));
        String http_status = cursor.getInt
(cursor.getColumnIndexOrThrow("http_status"));
        String create_time = cursor.getString(cursor.getColumnIndexOrThrow("create_time"));
        // 处理数据...
    }
} finally {
    cursor.close(); // 重要:必须关闭Cursor
}

// 方法2:使用rawQuery()
Cursor cursor = db.rawQuery("SELECT * FROM logs", null);
  • 更新数据

在 SQLite 数据库中更新数据,我们主要使用 update 方法。update 方法可以根据指定的条件,对表中的数据进行更新。如果更新成功,update 方法会返回受影响的行数;如果更新失败,会返回 0。

SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("create_time", "2026-01-02");


// 参数依次为:表名、更新内容、WHERE条件、WHERE参数
int count = db.update("logs", values,
 "create_time = ?",
 new String[] {"2026-01-01"});
  • 删除数据

在 SQLite 数据库中删除数据,我们使用 delete 方法。delete 方法可以根据指定的条件,从表中删除数据。如果删除成功,delete 方法会返回受影响的行数;如果删除失败,会返回 0。

SQLiteDatabase db = dbHelper.getWritableDatabase();


// 参数依次为:表名、WHERE条件、WHERE参数
int deletedRows = db.delete("logs", "id = ?", new String[] {String.valueOf(rowId)});
  • 事务处理

事务是数据库操作中的一个重要概念,它可以将一组相关的数据库操作组合在一起,确保这些操作要么全部成功执行,要么一个都不执行(即全部回滚到未执行的状态),这被称为事务的原子性。事务的作用主要体现在两个方面:保障数据的一致性和提高执行性能。

在批量数据操作时,事务还能显著提高执行性能。默认情况下,SQLite 会为每个插入、更新或删除操作开启一个隐式事务并立即提交,这意味着如果我们要进行多次这样的操作,就会频繁地进行磁盘 I/O 操作,因为每次提交事务都可能涉及到磁盘的写入。而当我们将多次操作放在一个手动的事务中时,这些操作会被暂时缓存,直到事务结束时才一次性提交,这样可以大大减少磁盘 I/O 的次数,从而提高性能。

SQLiteDatabase db = dbHelper.getWritableDatabase();

// 开启一个事务
db.beginTransaction();
try {
    // 执行多个操作
    ContentValues values1 = new ContentValues();
    values.put("id", 2);
	values.put("http_status", 2);
	values.put("create_time", "2026-01-02");
    db.insert("logs", null, values);
    
    ContentValues values2 = new ContentValues();
    values.put("id", 3);
	values.put("http_status", 3);
	values.put("create_time", "2026-01-03");
    db.insert("logs", null, values2);
    
    db.setTransactionSuccessful(); // 标记事务成功
} catch (Exception e) {
    // 事务失败会自动回滚
    e.printStackTrace();
} finally {
    db.endTransaction(); // 结束事务
}

6、实际使用示例

package com.sqlitelibrary;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;

public class SQLiteOpenHelperManage extends SQLiteOpenHelper {

    public SQLiteOpenHelperManage(Context context, String filename, String dbName, int version){
        super(context, getDatabasePath(filename, dbName), null, version);
    }

    /**
     * 获取数据库路径
     * @param dbName
     * @return
     */
    private static String getDatabasePath(String filename, String dbName) {
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Log.d("SD卡不可用", "");
            return null;
        }

        File publicDir = new File(Environment.getExternalStorageDirectory(), filename);

        if (!publicDir.exists()) {
            boolean isMkdirs = publicDir.mkdirs();
            Log.d("mkdirs", "isMkdirs: " + isMkdirs);
        }

        String path = publicDir.getAbsolutePath();
        // 使用这个路径来创建或访问数据库文件
        File dbFile = new File(path, dbName + ".db");
        if (!dbFile.exists()) {
            try {
                boolean isCreateNewFile = dbFile.createNewFile();
                Log.d("createNewFile", "isCreateNewFile: " + isCreateNewFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dbFile.getAbsolutePath();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
		// 首次创建数据库时调用,用于建表

    }

    // 更新数据库表与数据库表字段
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
		 // 数据库版本升级时调用,通常用于表结构变更

    }

    /**
     * 创建数据库表
     * @param sql
     * @return
     */
    public String createTable (String sql) {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.execSQL(sql);
            return "创建成功";
        } catch (SQLiteException e) {
            return e.getMessage();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    /**
     * 执行sql语句
     * @param sql
     * @return
     */
    public String executeSql(String sql){
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.execSQL(sql);
            return "执行成功";
        } catch (SQLiteException e) {
            return e.getMessage();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    /**
     * 查询数据
     * @param sql
     * @return
     */
    public String selectSql(String sql) {
        JSONArray resultSet = new JSONArray();
        try {
            SQLiteDatabase db = getWritableDatabase();
            Cursor cursor = db.rawQuery(sql, null);
            cursor.moveToFirst();
            while (cursor.isAfterLast() == false) {
                int totalColumn = cursor.getColumnCount();
                JSONObject rowObject = new JSONObject();

                for(int i=0 ;  i< totalColumn ; i++) {
                    if(cursor.getColumnName(i) != null) {
                        try {
                            if(cursor.getString(i) != null) {
                                rowObject.put(cursor.getColumnName(i), cursor.getString(i));
                            } else {
                                rowObject.put(cursor.getColumnName(i), "");
                            }
                        } catch (Exception e) {
                            // Log.d("userTable", e.getMessage()  );
                        }
                    }
                }
                resultSet.put(rowObject);
                cursor.moveToNext();
            }
            cursor.close();
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        Log.d("查询数据结果", "JSONArray: " + resultSet);
        Log.d("查询数据结果", "toString: " + resultSet.toString());
        return resultSet.toString();
    }

    /**
     * 判断数据库是否打开
     */
    public boolean isOpenDatabase() {
        try {
            SQLiteDatabase db = getWritableDatabase();
            return db.isOpen();
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

    /**
     * 关闭数据库
     */
    public boolean closeDatabase() {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.close();
            return true;
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

    /**
     *  开启事务
     */
    public boolean beginTransaction() {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.beginTransaction();
            return true;
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

    /**
     *  设置事务标志为成功,当结束事务时就会提交事务
     */
    public boolean setTransactionSuc() {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.setTransactionSuccessful();
            return true;
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

    /**
     *  结束事务
     */
    public boolean endTransaction() {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.endTransaction();
            return true;
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

    /**
     * 设置数据库版本
     */
    public boolean setDatabaseVersion(int version) {
        try {
            SQLiteDatabase db = getWritableDatabase();
            db.setVersion(version);
            return true;
        } catch (SQLiteException e) {
            Log.e("数据库异常", "SQLiteException: " + e.getMessage());
        } catch (Exception e) {
            Log.e("数据库异常", "Exception: " + e.getMessage());
        }
        return false;
    }

}

7、注意事项

  1. 数据库文件位置:/data/data/<包名>/databases/

  2. 数据库文件大小限制:理论上最大 140TB,但实际受设备存储限制。

  3. 并发访问:SQLite支持多线程读,但写操作需要同步。

  4. 数据类型:SQLite是动态类型,但建议按声明类型存储。

8、总结

SQLite 是一种轻量级的开源数据库框架,已经被预置到 Android 系统中,我们可以非常方便的使用。既可以通过标准的 SQL 语句进行操作,也可以使用Android 提供的 Java 接口做 CURD。无论选择哪种操作方式,都要注意数据库操作应在后台线程执行,并正确处理数据库的创建、升级和资源释放。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐