SQLite
SQLite是一个轻量级数据库,不同于MYSQL或MS-SQL等数据库服务系统,对于大多数用户而言,
SQLite具体的表现仅仅只是一个数据库文件而已。
SQLite占用资源非常低,占用的内存空间可能只需要几百kb,多用于嵌入式产品;
SQLite可支持Windows/Linux/Unix等主流操作系统,且支持主流的程序开发语言,例如
JAVA、C#、PHP等。
Android系统在其核心库已经实现了SQLite数据库引擎,开发人员只需要创建
应用程序所需要的数据库文件、构建数据表,即可实现数据库的增删改查操作;
SQLite数据库文件的权限依赖于操作系统,因此它没有用户账户的概念,各应用程序
独占自身所有的SQLite数据库文件。
SQLite数据库文件的扩展名应为.db,但由于它对于扩展名没有依赖性,因此,开发人员
可以不指定SQLite数据库文件的扩展名。
各应用程序的SQLite数据库文件保存在/data/data/应用程序包名/database/文件夹下。
与常用的数据库软件一样,SQLite中依然存在数据库 (表现为独立的文件)、数据表、
数据字段等概念,且支持绝大多数SQL92标准语法,以实现对数据表、数据的管理;
SQLite支持事务管理,但不支持完整的触发器、可写视图。
SQLite小特性:无需安装或配置,开源,支持数据库最大2TB,比一般的数据库的
执行效率更高。
SQLite是无类型的,即在创建数据表时可以不用指定字段(列)的数据类型,任意数据类型
的数据都可以保存在任意的字段中(列),但是建议在创建数据表时指定数据类型,
并合理的填充数据,以便于与别人之间的交流。
创建数据库与数据表
在Android系统中,创建数据库的方式有:
调用openOrCreateDatabase()方法
扩展SQLite类
调用ContextWrapper类定义的openOrCreateDatabase()方法即可打开或创建数据库,
即:
如果指定的数据库不存在,则先创建他,然后再打开;
如果指定的数据库已经存在,则直接打开它。
方法签名:
public SQLiteDatabase openOrCreateDatabase(String name,int mode,CursorFactory factory)
SQLiteDatabase类是在Android系统中用于执行各种相关操作的类,例如创建数据表、对数据进行
增删改查、执行事务等。
调用该类的exeSQL()方法可执行无需返回结果的SQL指令,该方法签名:
public void exeSQL(String sql) throws SQLException
使用一般创建数据表的SQL语法即可创建数据库,如果表名、字段名可能与
关键字冲突,可使用方括号:
CREATE TABLE [students](
[_id] INTEGER PRIMARY KEY AUTOINCREMENT,
[_name] VAECHAR(50) UNIQUE NOT NULL,
[_age] INT NOT NULL DEFAULT 15
)
新建一个数据库表的方法:
使用SQLiteOpenHelper类的相关方法也可以获取SQLiteDatabase类的对象,
以实现数据表、数据的相关操作;
SQLiteOpenHelper可更方便的实现数据库的初始化、版本更新等问题。
SQLiteOpenHelper类是抽象类,且没有无参数的构造方法,因此,开发人员定义其子类时,需要在子类的构造方法中显式
的调用该构造方法;
方法签名:
SQLiteOpenHelper类中的2个抽象方法约定了如何实现数据库的初始化与版本更新。
抽象方法签名:
DBOpenHelper:
在Activity中调用:
调用 SQLiteOpenHelper类的如下方法可获取SQLiteDatabase对象:
需要注意的是:getReadableDatabase()仍尝试获取一个可执行操作的数据库访问对象
(等效于getWritableDatabase()方法),仅当出现意外时,例如磁盘空间已满,则获取只读的数据库访问对象。
当第一次调用以上方法时,onCreate()、onUpgrade()方法可能被调用,而这2个方法可能消耗较长的执行时间,
因此建议不在主线程中调用以上方法。
向数据表中插入数据
使用execSQL(String sql,Object[] bindArgs)方法可以执行存在变量的SQL指令,
该方法签名如下:
在上边写出的一个类的基础上,在主Activity中加入以下语句即可实现数据的添加:
这种插入数据的方法不推荐,
另外一种插入数据的方法:
同样,在上面所提供的DBOpenHelper的前提下,在MainActivity中进行如下的修改:
如果显示插入成功,则说明成功插入了数据
ContentValues类以键值对(K-V)的形式封装了SQL语句中的字段名与值的对象,其中
K应为字段名,V应为对应的值,ContentValues本质是使用HashMap存储数据;
insert()方法的本质是根据方法的第1个、第3个参数拼接出SQL语句,如果第3个
参数无效(为null或没有值),则可能导致:
insert into table_name () values ()
第2个参数nullColumnHack仅当第3个参数无效时被使用,如果第2个参数被指定为
“username”且第3个参数无效时:
insert into table_name (username) values (null)
即第2个参数是为了保证SQL指令不出现语法错误而存在的,当
第3个参数无误时,第二个参数没有意义。
查询数据:
query()方法:参数说明:
1、 String table: 表名:
2、 String[] columns: 被检索的字段列表;
3、String selection: SQL语句中的where子句
4、String[] selectionArgs:SQL语句中的where子句的值
5、String groupBy:SQL语句中的group by子句
6、String having:SQL语句中的having子句
7、String orderBy: SQL语句中的order by子句
返回值说明:
返回Cursor对象,内部封装了查询到的数据。
Cursor接口:以类似JDBC中的ResultSet接口的方式存在的、定义了如何保存从数据库中读取的结果的接口;
常用的方法有:
int getColumnIndex(String columnName):根据字段名获取该字段的索引号;
int getInt(Int columnIndex)/float getFloat(int columnIndex)/String getString(int columnIndex)等;
根据字段索引获取值;
boolean moveToFirst() /boolean moveToLast() / boolean moveToPosition(int position)等:移动游标;
boolean isFirst() / boolean isLast() / boolean isBeforeFirst() / boolean isAfterLast():判断游标的位置;
在第1次使用Cursor时,应调用moveToXXX()系列方法确定游标的位置,然后再进行相关的操作。
Cursor接口中定义了close()方法,开发人员在使用完Cursor后应该及时调用该方法,以释放资源。
下面是一个在数据库中查找数据的例子:
DBOpenHelper:同上,
通过这次的学习,让我对SQLite有了一个很好的理解。
SQLite具体的表现仅仅只是一个数据库文件而已。
SQLite占用资源非常低,占用的内存空间可能只需要几百kb,多用于嵌入式产品;
SQLite可支持Windows/Linux/Unix等主流操作系统,且支持主流的程序开发语言,例如
JAVA、C#、PHP等。
Android系统在其核心库已经实现了SQLite数据库引擎,开发人员只需要创建
应用程序所需要的数据库文件、构建数据表,即可实现数据库的增删改查操作;
SQLite数据库文件的权限依赖于操作系统,因此它没有用户账户的概念,各应用程序
独占自身所有的SQLite数据库文件。
SQLite数据库文件的扩展名应为.db,但由于它对于扩展名没有依赖性,因此,开发人员
可以不指定SQLite数据库文件的扩展名。
各应用程序的SQLite数据库文件保存在/data/data/应用程序包名/database/文件夹下。
与常用的数据库软件一样,SQLite中依然存在数据库 (表现为独立的文件)、数据表、
数据字段等概念,且支持绝大多数SQL92标准语法,以实现对数据表、数据的管理;
SQLite支持事务管理,但不支持完整的触发器、可写视图。
SQLite小特性:无需安装或配置,开源,支持数据库最大2TB,比一般的数据库的
执行效率更高。
SQLite是无类型的,即在创建数据表时可以不用指定字段(列)的数据类型,任意数据类型
的数据都可以保存在任意的字段中(列),但是建议在创建数据表时指定数据类型,
并合理的填充数据,以便于与别人之间的交流。
创建数据库与数据表
在Android系统中,创建数据库的方式有:
调用openOrCreateDatabase()方法
扩展SQLite类
调用ContextWrapper类定义的openOrCreateDatabase()方法即可打开或创建数据库,
即:
如果指定的数据库不存在,则先创建他,然后再打开;
如果指定的数据库已经存在,则直接打开它。
方法签名:
public SQLiteDatabase openOrCreateDatabase(String name,int mode,CursorFactory factory)
SQLiteDatabase类是在Android系统中用于执行各种相关操作的类,例如创建数据表、对数据进行
增删改查、执行事务等。
调用该类的exeSQL()方法可执行无需返回结果的SQL指令,该方法签名:
public void exeSQL(String sql) throws SQLException
使用一般创建数据表的SQL语法即可创建数据库,如果表名、字段名可能与
关键字冲突,可使用方括号:
CREATE TABLE [students](
[_id] INTEGER PRIMARY KEY AUTOINCREMENT,
[_name] VAECHAR(50) UNIQUE NOT NULL,
[_age] INT NOT NULL DEFAULT 15
)
新建一个数据库表的方法:
主界面不需要改变,MainActivity:
package com.example.lianxi;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SQLiteDatabase db;
db = openOrCreateDatabase("number.db", MODE_PRIVATE, null);
String sql = "CREATE TABLE [students] ("
+"[_id] INTEGER PRIMARY KEY AUTOINCREMENT,"
+"[_name] VARCHAR(50) UNIQUE NOT NULL,"
+"[_age] INT NOT NULL DEFAULT 16"
+")";
db.execSQL(sql);
}
}
使用SQLiteOpenHelper类的相关方法也可以获取SQLiteDatabase类的对象,
以实现数据表、数据的相关操作;
SQLiteOpenHelper可更方便的实现数据库的初始化、版本更新等问题。
SQLiteOpenHelper类是抽象类,且没有无参数的构造方法,因此,开发人员定义其子类时,需要在子类的构造方法中显式
的调用该构造方法;
方法签名:
public SQLiteOpenHelper(Context context,String name,CursorFactory factory,int version)
SQLiteOpenHelper类中的2个抽象方法约定了如何实现数据库的初始化与版本更新。
抽象方法签名:
public void onCreate(SQLiteDatabase db)
public void onUpgrade(SQLiteDatabase db,int oldVersion ,int newVersion)
DBOpenHelper:
package com.example.lianxi;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBOpenHelper extends SQLiteOpenHelper{
public DBOpenHelper(Context context){
super(context,"number2.db",null,1);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String sql = "CREATE TABLE [students] ("
+"[_id] INTEGER PRIMARY KEY AUTOINCREMENT,"
+"[_name] VARCHAR(50) UNIQUE NOT NULL,"
+"[_age] INT NOT NULL DEFAULT 16"
+")";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
在Activity中调用:
DBOpenHelper helper = new DBOpenHelper(this);//使用这种方法可以反复执行
helper.getReadableDatabase();
调用 SQLiteOpenHelper类的如下方法可获取SQLiteDatabase对象:
public synchronized SQLiteDatabase getReadableDatabase()
public synchronized SQLiteDatabase getWritableDatabase()
需要注意的是:getReadableDatabase()仍尝试获取一个可执行操作的数据库访问对象
(等效于getWritableDatabase()方法),仅当出现意外时,例如磁盘空间已满,则获取只读的数据库访问对象。
当第一次调用以上方法时,onCreate()、onUpgrade()方法可能被调用,而这2个方法可能消耗较长的执行时间,
因此建议不在主线程中调用以上方法。
向数据表中插入数据
使用execSQL(String sql,Object[] bindArgs)方法可以执行存在变量的SQL指令,
该方法签名如下:
public void execsQL(String sql,Object[] bindArgs) throws SQLException
在上边写出的一个类的基础上,在主Activity中加入以下语句即可实现数据的添加:
这种插入数据的方法不推荐,
DBOpenHelper helper = new DBOpenHelper(this);//使用这种方法可以反复执行
SQLiteDatabase db = helper.getReadableDatabase();
String sql = "INSERT INTO students (name,age) VALUES(?,?)";
Object[] bindArgs = new Object[] {"Jaskdk",34};
db.execSQL(sql, bindArgs);
另外一种插入数据的方法:
同样,在上面所提供的DBOpenHelper的前提下,在MainActivity中进行如下的修改:
DBOpenHelper helper = new DBOpenHelper(this);//使用这种方法可以反复执行
SQLiteDatabase db = helper.getReadableDatabase();
String table = "students";
String nullColumnHack = null;
ContentValues values = new ContentValues();
values.put("_name", "Mike");
values.put("_age", 28);
long id = db.insert(table, nullColumnHack , values);
if(id == -1){
Toast.makeText(this, "错误", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this, "插入记录成功", Toast.LENGTH_LONG).show();
}
如果显示插入成功,则说明成功插入了数据
ContentValues类以键值对(K-V)的形式封装了SQL语句中的字段名与值的对象,其中
K应为字段名,V应为对应的值,ContentValues本质是使用HashMap存储数据;
insert()方法的本质是根据方法的第1个、第3个参数拼接出SQL语句,如果第3个
参数无效(为null或没有值),则可能导致:
insert into table_name () values ()
第2个参数nullColumnHack仅当第3个参数无效时被使用,如果第2个参数被指定为
“username”且第3个参数无效时:
insert into table_name (username) values (null)
即第2个参数是为了保证SQL指令不出现语法错误而存在的,当
第3个参数无误时,第二个参数没有意义。
查询数据:
query()方法:参数说明:
1、 String table: 表名:
2、 String[] columns: 被检索的字段列表;
3、String selection: SQL语句中的where子句
4、String[] selectionArgs:SQL语句中的where子句的值
5、String groupBy:SQL语句中的group by子句
6、String having:SQL语句中的having子句
7、String orderBy: SQL语句中的order by子句
返回值说明:
返回Cursor对象,内部封装了查询到的数据。
Cursor接口:以类似JDBC中的ResultSet接口的方式存在的、定义了如何保存从数据库中读取的结果的接口;
常用的方法有:
int getColumnIndex(String columnName):根据字段名获取该字段的索引号;
int getInt(Int columnIndex)/float getFloat(int columnIndex)/String getString(int columnIndex)等;
根据字段索引获取值;
boolean moveToFirst() /boolean moveToLast() / boolean moveToPosition(int position)等:移动游标;
boolean isFirst() / boolean isLast() / boolean isBeforeFirst() / boolean isAfterLast():判断游标的位置;
在第1次使用Cursor时,应调用moveToXXX()系列方法确定游标的位置,然后再进行相关的操作。
Cursor接口中定义了close()方法,开发人员在使用完Cursor后应该及时调用该方法,以释放资源。
下面是一个在数据库中查找数据的例子:
MainActivity:
package com.example.lianxi;
import android.app.Activity;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private DBOpenHelper helper;
private SQLiteDatabase db;
private EditText name;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
helper = new DBOpenHelper(this);
db = helper.getReadableDatabase();
name = (EditText) findViewById(R.id.name);
}
public void find_All(View view){
Cursor cursor = db.query("students", new String[]{"_id","_name","_age"}, null, null, null, null, "_id desc");
long id;
String name;
int age;
for(cursor.moveToFirst(); !cursor.isAfterLast();cursor.moveToNext()){
id = cursor.getLong(cursor.getColumnIndex("_id"));
name = cursor.getString(cursor.getColumnIndex("_name"));
age = cursor.getInt(cursor.getColumnIndex("_age"));
System.out.println("id = " + id + " ," + "name = " +name +" ," + "age = " + age);
}
cursor.close();
}
public void findName(View view){
String findName = name.getText().toString();
Cursor cursor = db.query("students", null, "_name=?", new String[]{findName}, null, null, null);
if(cursor.moveToFirst()){
long id1;
String name1;
int age1;
id1 = cursor.getLong(cursor.getColumnIndex("_id"));
name1 = cursor.getString(cursor.getColumnIndex("_name"));
age1 = cursor.getInt(cursor.getColumnIndex("_age"));
Toast.makeText(this, "学生记录为id = " + id1 + " ," + "name = " +name1 + " ," + "age = " + age1, Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this, "没有匹配的记录!", Toast.LENGTH_LONG).show();
}
}
}
DBOpenHelper:同上,
整体布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/find_all"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="find_All"
android:text="查询所有数据" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="30dp"
android:orientation="horizontal" >
<EditText
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10" >
</EditText>
<Button
android:id="@+id/find"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:onClick="findName"
android:text="查询" />
</LinearLayout>
</LinearLayout>
通过这次的学习,让我对SQLite有了一个很好的理解。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理