本文目录:
1. 创建数据库
2. 升级数据库
3. 添加数据
4. 更新数据
5. 删除数据
6. 查询数据
分割线
(本文原理内容来自《Android第一行代码(第二版)》)
介绍:
SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。
SQLite不仅支持标准的SQL语法,还遵循数据库的ACID事务,所以只要你以前使用过其他的关系型数据库,就可以很快地上手 SQLite。
SQLite比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。
Android正是把这个功能极为强大的数据库嵌入到了系统当中,使得本地持久化的功能有了一次质的飞跃。
1. 创建数据库
Android提供了一个SQLiteOpenHelper
帮助类,用于对数据库进行创建和升级
SQLiteOpenHelper
是一个抽象类,使用时需要创建自己的类去继承它。
SQLiteOpenHelper
有两个抽象方法onCreate()
和onUpgrade()
,必须在自己的类中重写这两个方法,然后分别在这两个方法中实现创建
和升级
数据库的逻辑。
SQLiteOpenHelper
中还有两个非常重要的实例方法: getReadableDatabase()
和 getWritableDatabase()
。
这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。
不同的是,当数据库不可写入的时候(如磁盘空间已满),
getReadableDatabase()
方法返回的对象将以只读的方式去打开数据库
getWritableDatabase()
方法则将出现异常
SQLiteOpenHelper
中有两个构造方法可供重写,一般使用参数少的那个构造方法即可。
这个构造方法中接收4个参数:
第一个参数
是 Context,必须要有它才能对数据库进行操作。
第二个参数
是数据库名,创建数据库时使用的就是这里指定的名称。
第三个参数
允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。
第四个参数
表示当前数据库的版本号,可用于对数据库进行升级操作。
构建出SQLiteOpenHelper
的实例之后,再调用它的 getReadableDatabase()
或 getWritableDatabase()
方法就能够创建数据库了,数据库文件会存放在/data/data/
日录下。此时重写的 onCreate()
方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑。
Demo:
我们希望创建一个名为
BookStore
的数据库,并在这个库中创建一张Book
表,表中有id、作者、价格、页数和书名。
(SQLite中integer
代表整型,real
表示浮点型,text
表示文本类型,blob
表示二进制类型)
- 新建MyDatabaseHelper类继承自SQLiteOpenHelper
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
private Context mContext;
public MyDatabaseHelper(Context context, String name,SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
这里将建表语句定义为字符串常量,并在onCreate()
方法中调用了execSQL()
方法执行建表语句。
- activity_main.xml文件
布局里只加入了一个按钮,用于创建数据库
- MainActivity代码
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
//创建数据
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
}
这里我们在onCreate()
方法中构建了一个MyDatabaseHelper
对象,并且通过构造函数的参数将数据库名指定为BookStore.db
,版本号指定为1
,然后在Create database
按钮的点击事件里调用了getWritableDatabase()
方法。这样当第一次点击Create database
按钮时,就会检测到当前程序中并没有BookStore.db
这个数据库,于是会创建该数据库并调用MyDatabaseHelper
中的onCreate()
方法,这样Book表也就得到了创建,然后会弹出一个Toast提示创建成功。再次点击Create database
按钮时,会发现此时已经存在BookStore.db
数据库了,因此不会再创建一次
此时BookStore.db
数据库和Book
表已经创建成功了,因为当你再次点击Create database
按钮时,不会有Toast
弹出。
2. 升级数据库
现在已经有了一个Book表用于存放书的各种详细数据,如果想再添加一张Category表用于记录图书的分类,怎么办呢?
- 在MyDatabaseHelper中添加语句:
此时运行程序,Category
表并没有创建成功,因为之前我们的BookStore.db数据库已经存在了,不管怎样点击Create database按钮,MyDatabaseHelper中的onCreate()方法都不会执行,也就无法创建新表了。
解决这个问题就要用到升级数据库
功能
- 在MyDatabaseHelper的onUpgrade()函数中加入以下语句
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
- 现在我们需要让onUpgrade()方法得到执行,修改SQLiteOpenHelper构造方法的第四个参数,之前设置的1,现在传入一个大于1的值,表示我们对数据库进行升级了。
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
//创建数据
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
}
重新运行程序,Category表就创建成功了。
3. 添加数据
SQLiteDatabase中提供了一个insert()
方法,用于添加数据。
它接受3个参数
第一个参数
:表名
第二个参数
:用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,我们一般直接传入null
第三个参数
:一个ContentValues
对象,它提供了一系列put()方法重载,用于向ContentValues中添加数据,只需将表中的每个列名以及对应的数据传入即可。
Demo:
- activity_main.xml中加入Add data按钮控件
- 更改MainActivity代码,onCreate()中加入代码
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
//创建数据
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
//添加数据
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 开始组装第一条数据
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values); // 插入第一条数据
values.clear();
// 开始组装第二条数据
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values); // 插入第二条数据
}
});
}
}
在添加数据按钮的点击事件里面,我们先获取到了SQLiteDatabase对象,然后使用ContentValues
来对要添加的数据进行组装。
这里只对Book表里其中四列的数据进行了组装,id那一列没并没给它赋值。这是因为在前面创建表的时候,我们就将id列设置为自增长了,它的值会在入库的时候自动生成,所以不需要手动给它赋值了。
接下来调用了insert()
方法将数据添加到表当中,注意这里我们实际上添加了两条数据,上述代码中使用 Contentvalues分别组装了两次不同的内容,并调用了两次 insert()方法。
重新运行程序,点击ADD DATA
按钮便可在表中添加数据了
4. 更新数据
关于更新数据,SQLiteDatabase中提供了一个update()
方法,用于对数据更新。
该方法接受4个参数
第一个参数
:表名
第二个参数
:Contentvalues对象,在这里把要更新的数据组装进去
第三个参数
和第四个参数
:用于约束更新某一行或某几行的数据(默认更新所有行)
Demo:
- activity_main.xml中加入update data按钮控件
- 更改MainActivity代码,onCreate()中加入代码
//更新数据
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
}
});
这里在更新数据按钮的点击事件里面构建了一个 ContentValues
对象,并且只给它指定了一组数据,说明我们只是想把价格这一列的数据更新成10.99。然后调用了SQLiteDatabase的update()
方法去执行具体的更新操作,可以看到,这里使用了第三、第四个参数来指定具体更新哪几行。第三个参数对应的是SQL语句的 where部分,表示更新所有name等于?的行,而?是一个占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容。因此上述代码想表达的意图是将名字是 The Da Vinci Code
的这本书的价格改成10.99。
5. 删除数据
SQLiteDatabase中提供了一个delete()
方法,用于删除数据。
该方法接受3个参数
第一个参数
:表名
第二个参数
和第三个参数
:用于约束删除某一行或某几行的数据(默认删除所有行)
Demo:
- activity_main.xml中加入delete data按钮控件
- 更改MainActivity代码,onCreate()中加入代码
//删除数据
Button deleteButton = (Button) findViewById(R.id.delete_data);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });
}
});
程序指定删除那些页数超过500页的书
6. 查询数据
SQLiteDatabase中提供了一个query()
方法,用于对数据进行查询。
该方法参数比较复杂,最短的一个重载方法也需要7个参数
第一个参数
:表名
第二个参数
:指定查询的列名(默认所有列)
第三个参数
:和第四个参数
:用于约束查询某一行或某几行的数据(默认查询所有行)
第五个参数
:指定需要group by的列,不指定则不进行group by操作
第六个参数
:对group by之后的数据进一步过滤
第七个参数
:指定查询结果的排序方式
Demo:
- activity_main.xml中加入query data按钮控件
- 更改MainActivity代码,onCreate()中加入代码
//查询数据
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("MainActivity", "book name is " + name);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book pages is " + pages);
Log.d("MainActivity", "book price is " + price);
} while (cursor.moveToNext());
}
cursor.close();
}
});
我们首先在查询按钮的点击事件里面调用了SQLiteDatabase的query()方法查询数据。这里的query()方法非常简单,只是使用了第一个参数指明去查询Book表,后面的参数全部为null,表示希望查询这张表中的所有数据。虽然这张表中目前只剩下一条数据了。査询完之后就得到了一个Cursor
对象,接着我们调用它的 moveToFirst()
方法将数据的指针移动到第一行的位置,然后进入了一个循环当中,去遍历查询到的每一行数据。在这个循环中可以通过Cursor的getColumnIndex()
方法获取到某一列在表中对应的位置索引,然后将这个索引传入到相应的取值方法中,就可以得到从数据库中读取到的数据了。接着我们使用Log将数据打印出来。最后别忘了调用close()
方法关闭Cursor。
重新运行程序,可以看到logcat打印的内容如下: