Android 为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper 帮助类,借助这个类就可以非常简单地对数据库进行创建和升级。
首先,SQLiteOpenHelper 是一个抽象类,如果需要使用它的话,就需要创建一个自己的帮助类去继承它,SQLiteOpenHelper 类有两个重要的方法,分别是 onCreat() 和 onUpgrade() ,也就是创建数据库和升级数据库的方法,我们必须在自己的帮助类中重写这两个方法,然后分别在这俩个方法中去实现创建,升级数据库的逻辑。
SQLiteOpenHelper 中还有两个非常重要的实例方法,getReadableDatabase() 和 getWritableDatabase() 方法,这两个方法都可以创建或者打开一个现有的数据库(如果存在则就打开,否则就创建),并返回一个可以对数据库进行读写操作的对象,他们都可以进行读和写的操作,但是不同的是,当数据库不可写入的时候(如磁盘控件已满),getReadableDatabase() 会返回的对象将以只读的方式去打开数据库,而 getWritableDatabase() 则会出现异常。
首先创建一个自己的帮助类,MyDataBaseHleper, 这里使用了参数较少的那个构造方法,表名为 book, 字段有 author 作者,price 加个,pages 页数,name 书名。
public class MyDataBaseHelper extends SQLiteOpenHelper {
/**
* primary key 将 id 设为主键
* <p/>
* autoincrement 表示 id 列是自增长的
* <p/>
* real 表示浮点型
* <p/>
* blob 表示二进制类型
*/
private final String CREATE_BOOK = "create table book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
private Context context;
/**
* @param context context
* @param name 数据名
* @param factory 允许在查询数据的时候返回一个自定义的 Cursor,一般传 null
* @param version 数据库版本号
*/
public MyDataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}
/**创建*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(context, "数据库创建成功", Toast.LENGTH_SHORT).show();
}
/**升级*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
接下来就可以去创建数据库了,我是在一个 Activity 里面写的,
public class DdActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
final MyDataBaseHelper dataBaseHelper = new MyDataBaseHelper(this,"BookStore.db",null,1);
Button button = (Button) findViewById(R.id.btn);
if (button != null)
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dataBaseHelper.getWritableDatabase();
}
});
}
}
首先创建了一个自己的帮助类 MyDataBaseHelper 的实例,传入了一个 上下文,数据库的名字,cursor 为 null ,版本号是 1,然后在 Button 中执行 getWritableDatabase() 方法,然后点击的时候就会有数据库创建成功的提示,再次点击的时候因为数据库已经被创建,所以没有任何的提示。
如果想要查看数据文件,在虚拟机上的话,可以直接打开 DDMS 然后在上面的 File Explore 选项卡中的 data/data/你的包名/databases 就会发现你创建的数据库文件,以.db 结尾的那个,导出之后,用查看数据库的工具就可以查看了,至于真机上,因为一些权限的问题 ,有时间在补上吧。。。
接下来我们来说说,数据库的升级操作,这个分为两种情况,一种是不保留原始数据,一种是保留原始数据,先看看第一种情况
不保留原始数据的情况
比如,我们还需要一张表,首先,写一个 SQL 语句
public final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text, "
+ "category_code integer)";
这个跟上面的那个语句差不多,名字真机随意就好了。然后在 onCreate() 方法中添加执行这个语句
/**创建*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
/**新添加的*/
db.execSQL(CREATE_CATEGORY);
Toast.makeText(context, "数据库创建成功", Toast.LENGTH_SHORT).show();
}
在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);
}
这个语句的意思就是,如果存在这张表就删除,然后执行 onCreate() 方法,当然不要忘了把数据库的版本号改一下,大于之前的就好。
new MyDataBaseHelper(this,"BookStore.db",null,2);
OK,这样就可以了,再次点击的时候,就会有提示创建成功
再来说说第二种情况,保留原始数据的,其实远离也很简单,就是把原来的表名改成临时表,然后新建一张表(名字看你自己喽)把临时表的数据导入道这张新表中就可以了。
我们还需要几个 SQL 语句
创建一张临时表
private final String CREATE_TEMP_BOOK = "alter table book rename to _temp_book";
创建一个新的 book 表
private final String CREATE_NEW_BOOK = "create table book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "pages integer, "
+ "name text)";
把临时表中的所有列都复制道新的 book 表中
private String INSERT_DATA = "insert into book select * from _temp_book";
有选择行的把临时表中的列复制道新的 book 表中
private final String INSERT_DATA = "insert into book select id,author,pages,name from _temp_book";
上面的两条语句根据自己的需求使用就好,如果两张表的格式相同就可以选择上面的那个,否则就可以添加一些字段名来控制
删除临时表
private final String DROP_TEMP_BOOK = "drop table _temp_book";
然后从新编写 onUpgrade() 方法
/**升级*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (newVersion){
case 3:
db.execSQL(CREATE_TEMP_BOOK);
db.execSQL(CREATE_NEW_BOOK);
db.execSQL(INSERT_DATA);
db.execSQL(DROP_TEMP_BOOK);
break;
}
}
最后别忘了更改版本号,再次点击创建就升级完成了,其实原理还是很简单的,就是一些 SQL 语句,其实我也不是搞数据库的。。。
终于到了增删改查的环节了
dataBaseHelper.getWritableDatabase()
这个方法会返回一个 SQLiteDatabase 对象 我们可以利用这个对象来就行一些数据的操作,好了,上代码,这个刚开始的时候版本号是 2 ,如果想要升级测试需要改成 3
public class DdActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
final MyDataBaseHelper dataBaseHelper = new MyDataBaseHelper(this, "BookStore.db", null, 2);
Button btnCreate = (Button) findViewById(R.id.btn_create);
Button btnAdd = (Button) findViewById(R.id.btn_add);
Button btnDelete = (Button) findViewById(R.id.btn_delete);
Button btnUp = (Button) findViewById(R.id.btn_up);
Button btnQuery = (Button) findViewById(R.id.btn_query);
/**创建*/
assert btnCreate != null;
btnCreate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dataBaseHelper.getWritableDatabase();
}
});
/**添加*/
assert btnAdd != null;
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase sqLiteDatabase = dataBaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 开始组装第一条数据
values.put("name", "MyBook");
values.put("author", "wy");
values.put("pages", 100);
//values.put("price", 30.96);
/**
* 参数1:表名
* 参数2:用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,
* 就是当 values为 null 或者 values.size() 为 0 的时候,可以
* 添加一个列的名字,然后就会给这个列的值赋值为 null.
* 参数3:没啥说的,以键值对存数据的一个对象
* */
sqLiteDatabase.insert("book", null, values);
}
});
/**删除*/
assert btnDelete != null;
btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
/**pages > ? 删除pages是大于 100 的书 */
/** 所有符合条件的都会生效 */
db.delete("book", "pages > ?", new String[] {"90"});
}
});
/**更新*/
assert btnUp != null;
btnUp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("author","wlq");
/**
* 第三、第四个参数来指定具
* 体更新哪几行。第三个参数对应的是SQL 语句的where 部分,表示去更新所有name 等于?
* 的行,而?是一个占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每
* 个占位符指定相应的内容
*
* 所有符合条件的都会生效
* */
db.update("book",contentValues,"name = ?",new String[]{"MyBook"});
}
});
/**查询*/
assert btnQuery != null;
btnQuery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
//参数解释
/**
* String table 哪个表 table,要查询的哪个表
*
* String[] columns 返回哪一列,如果参数是null,则返回所有列
*
* String selection 返回哪一行的过滤器,格式是SQL的WHERE,
* 设置为null,返回这个table的所有行
*
* String[] selectionArgs 在selection字段中可能会用'?'的形式来加一些额外的参数,
* 这个的selectionArgs字段就是把selection字段的条件填充好
*
* String groupBy 一个过滤器,如何来分组---设置为null则不分组
*
* String having 分组后聚合的过滤条件
*
* String orderBy 排序,格式是SQL的ORDER一样.设置null使用默认
*
* String limit 返回的行数(几行),设置为null表示没有限制.
*/
//查询所有列
Cursor cursor = db.query("book", null, null, null, null, null, null);
//添加限制条件 查询 name 列的 author = wy 的数据,返回 name 列数据,不返回其他列
Cursor cursor = db.query("book",new String[]{"name"},
"author = ?",new String[]{"wy"},null,null,null);
if (cursor.moveToFirst()) {
do {
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.e("MainActivity", "book name is " + name);
Log.e("MainActivity", "book author is " + author);
Log.e("MainActivity", "book pages is " + pages);
// Log.e("MainActivity", "book price is " + price);
} while (cursor.moveToNext());
cursor.close();
}
}
});
}
}
收工