android系统内置了数据库,SQLite作为一种轻量级的关系型数据库,它的运算速度非常快。占用资源很少,通常只需要几百k的内存就足够了,之前多介绍的两种方式只适合去存储一些简单的数据和键值对,当蓄呀存储大量的复杂的关系型数据的时候,就会发现以上两种存储方式很难应付。下面开始介绍在android中如何使用SQLite数据库。
1 创建数据库
android为了让我们更加方便的管理数据库,专门为我们提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单的对数据库尽享创建和升级,下面我主要介绍一下这个类的一些基本用法。
SQLiteOpenHelper类是一个抽象类,主要有两个抽象方法,分别是onCreate和onUpgrade(),我们必须在自己的帮助类中去重写这两个方法,分别在这两个类中去实现创建和升级数据库的逻辑。
SQLiterOpenHelper中还有两个非常重要的实力方法,getReadableDatabase()和getWritablebase(),这两个方法都可以创建或打开一个现有的数据库并返回一个可以对数据库进行读写操作的对象,需要注意的是,当数据库不可写入的时候,getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWiterableDatabase()方法则将会出现异常。
SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少点的那个,这个构造方法接受四个参数,第一个参数Context,这个没什么好说的,第二个参数是数据库名,第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null,第四个参数表示当前数据库的版本号。构建出SQLiteOpenHelper的实例之后,再调用他的getReadableDatabase()或getwritableDatabase()方法就能够创建数据库了,重写的onCreate()方法也会得到执行。
接下来根据一个例子,创建一个BookStrore.db的数据库,并对其进行添加(insert),更新(update),删除(delete),查询(quary).
创建SQLiteOpenHelper类的实例代码:
package com.example.apple.servicetest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
* Created by apple on 16/3/22.
*/
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK="create table Book(" +
"id interger primary key autoincrement" +
"author text" +
"price real" +
"pages integer" +
"name text)";
public static final String CREATE_CATEGORY="create table Category(" +
"id integer primary key autoincrement" +
"category_name text," +
"category_code integer)";
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);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext,"successed",Toast.LENGTH_LONG).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exist Category");
onCreate(db);
}
}
对数据库进行操作:
package com.example.apple.servicetest;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private Button createbtn;
private Button adddatabtn;
private Button updatabtn;
private Button deletebtn;
private Button quarybtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createbtn=(Button)findViewById(R.id.create_btn);
final MyDatabaseHelper databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
createbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
databaseHelper.getWritableDatabase();
}
});
//更新数据
updatabtn=(Button)findViewById(R.id.updata_btn);
updatabtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db=databaseHelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "name=?", new String[]{"love is good"});
}
});
//删除数据
deletebtn=(Button)findViewById(R.id.delete_data);
deletebtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db=databaseHelper.getWritableDatabase();
db.delete("Book", "pages>?", new String[]{"500"});
}
});
//查询数据
quarybtn=(Button)findViewById(R.id.quary_btn);
quarybtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db=databaseHelper.getWritableDatabase();
Cursor cursor=db.query("Book",null,null,null,null,null,null);
if (cursor.moveToFirst()){
do {
String name=cursor.getString(cursor.getColumnIndex("name"));
String author=cursor.getString(cursor.getColumnIndex("author"));
Log.d("lallalala",name);
Log.d("youyouyouyou",author);
}while (cursor.moveToNext());
}
cursor.close();
}
});
//添加数据
adddatabtn=(Button)findViewById(R.id.add_btn);
adddatabtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db=databaseHelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("name","love is good");
values.put("author","dan brown");
values.put("pages",454);
values.put("price",16.96);
db.insert("Book", null, values);
values.clear();
values.put("name","love is bad");
values.put("author","dan ");
values.put("pages",400);
values.put("price", 19.00);
db.insert("Book", null, values);
}
});
}
}
这是其中一种方法来操作数据库,还有一种是使用SQL来操作数据库,具体代码实现如下:
更新数据库
删除数据库
db.execSQL("delete from Book where pages>?",new String[]{"500"});
更新数据库
db.execSQL("update Book set price =? where name=?",new String[] {"10.99","the name"});
添加数据库
db.execSQL("insert into Book(name,author,pages,price) values(?,?,?,?)", new String[] {"the name","the author","454","19.69"});
查找数据库
db.rawQuery("select * from Book",null);
SQLite数据库的最佳实践
1 使用事务
我们已经知道了SQLite数据库是支持事务的,事务的特性可以保证让某一系列的操作要么全部完成,要么一个都不会完成,那么在什么情况下才需要使用事务,据个例子,在尽享一次转账操作的时候,银行会将转账的金额先从账户中扣除,然后再向收款房的账户中添加等量的金额,但是如果当刚刚从 账户将钱扣除了之后,由于一些异常导致了对方收款失败了,那么这部分的钱就会凭空消失了,这时候就必须使用事务。
接下来将会在这个例子中使用事务,目的是将删除旧数据和添加新数据的操作一起完成,否则就必须还原成原来的旧数据。
SQLiteDatabase db=databaseHelper.getWritableDatabase();
db.beginTransaction();
try {
db.delete("Book",null,null);
if (true){
throw new NullPointerException();
}
ContentValues values=new ContentValues();
values.put("name","Game of Throns");
values.put("author","George Martin");
values.put("pages",720);
values.put("price",20.85);
db.insert("Book", null, values);
db.setTransactionSuccessful();
}catch (Exception e){
e.printStackTrace();
}finally {
db.endTransaction();
}
}
现在可以运行一下程序,发现表中的数据还是原先的那些,现在将手动抛出的异常删除掉,再运行议席,便发现表中的数据已经更新成新的数据了。
升级数据库的最佳写法:
再之前的写法中我们简单粗暴的直接删掉了所有当前的表然后强制重新执行一遍onCreate()方法。我们需要进行一些合理的控制,让我们保证在升级数据库的时候数据不会丢失,在第一版的时候创建两个,在第二版的时候在book表中添加category_id键。代码如下:
package com.example.apple.servicetest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
* Created by apple on 16/3/22.
*/
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK="create table Book(" +
"id interger primary key autoincrement" +
"author text" +
"price real" +
"pages integer" +
"name text" +
"category_id integer)";
public static final String CREATE_CATEGORY="create table Category(" +
"id integer primary key autoincrement" +
"category_name text," +
"category_code integer)";
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);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext,"successed",Toast.LENGTH_LONG).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//db.execSQL("drop table if exists Book");
//db.execSQL("drop table if exist Category");
//onCreate(db);
switch (oldVersion){
case 1:
db.execSQL(CREATE_CATEGORY);case 2:
db.execSQL("alter table Book add column category_id integer");//在第二版中添加的数据
default:
}
}
}
请注意一个非常重要的细节,switch中的每一个case的最后都没有使用break的原因,是为了保证在跨版本升级的时候,每一次的数据库修改都能被全部执行到,比如从当前的第二版升级到第三版的时候,case2中的逻辑就会执行,如果用户从第一版程序升级到第三版程序的时候,case1和case2也会被执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据也完全不会丢失了。