Android基础之十四数据存储 之 SQLite数据库详解
2016-05-17 16:19
441 查看
Android基础之十四数据存储 之 SQLite数据库详解
SQLite 是一款 轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百 K 的内存就足够了,因而特别适合在移动设备上使用。SQLite 不仅支持标准的 SQL 语法,还遵循了数据库的 ACID( 原子性(Atomicity) 、一致性(Consistency) 、 隔离性(Isolation) 、 持久性(Durability))事务,所以只要你以前使用过其他的关系型数据库,就可以很快地上手 SQLite。而 SQLite 又比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。Android 正是把这个功能极为强大的数据库嵌入到了系统当中,使得本地持久化的功能有了一次质的飞跃。
1 创建数据库
Android 为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper帮助类, 借助这个类就可以非常简单地对 数据库进行创建和升级‘
SQLiteOpenHelper 中有两个构造方法可供重写, 一般使用参数少一点的那个构造方法即
可。这个构造方法中接收四个参数,第一个参数是 Context 第二个参数是 数据库名, 创建数据库时使用的就是这里指定的名
称。第三个参数允许我们在查询数据的时候的 返回一个自定义的 Cursor,一般都是传入 null。
第四个参数表示 当前数据库的版本号,可用于 对数据库进行升级操作
MyDatabaseHelper(context, "BookStore.db", null, 1);
<span style="font-size:14px;">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, 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) { } }</span>2 升级数据库
如果你足够细心, 一定会发现 MyDatabaseHelper 中还有一个空方法呢! 没错, onUpgrade()方法是用于对数据库进行升级的, 它在整个数据库的管理工作当中起着非常重要的作用, 可千万不能忽视它哟。目前 DatabaseTest 项目中已经有一张 Book 表用于存放书的各种详细数据,如果我们想
张 再添加一张 Category 表用于记录书籍的分类该怎么做呢?
package com.example.sqllitehelp; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; public class MyDatabaseHelper extends SQLiteOpenHelper { public static final String CREATE_BOOK="create table Book (" +"id integer primary key autoincrement ," +"author test , " +"price real , " +"pages integer , " +"name text) " ; public static final String CREATE_CATEGORY="create table Category (" +"id integer primary key autoincrement ," +"category_name test , " +"category_code integer)" ; private Context mContext; public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub mContext=context; } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL(CREATE_BOOK); db.execSQL(CREATE_CATEGORY); Toast.makeText(mContext, "create successed", Toast.LENGTH_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub db.execSQL("drop table if exists Book"); db.execSQL("drop table if exists Category"); onCreate(db); Toast.makeText(mContext, "删除数据", Toast.LENGTH_SHORT).show(); } }MyDatabaseHelper(context, "BookStore.db", null, 1); 把这里的版本号改成2就可以执行升级方法了
3 添加数据
public class MainActivity extends Activity { 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 addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new 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); // 插入第二条数据 } }); } }4 更新数据
public class MainActivity extends Activity { 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 updateData = (Button) findViewById(R.id.update_data); updateData.setOnClickListener(new 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" }); } }); } }db.update("Book", values, "name = ?", new String[] { "The DaVinci Code" }) 这句话相当于 Update Book set price=10.99 where name=’The DaVinci Code"‘
5 删除数据
<span style="font-size:14px;">public class MainActivity extends Activity { 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 deleteButton = (Button) findViewById(R.id.delete_data); deleteButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete("Book", "pages > ?", new String[] { "500" }); } }); } }</span>db.delete("Book", "pages > ?", new String[] { "500" }); 相当于 delete from Book where pages>500
6 查询数据
public class MainActivity extends Activity { 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 queryButton = (Button) findViewById(R.id.query_data); queryButton.setOnClickListener(new 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(); } }); } }7 使用 SQL 操作数据库
下面我就来简略演示一下, 如何直接使用 SQL 来完成前面几小节中学过的 CRUD 操作。添加数据的方法如下:
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });
更新数据的方法如下:
db.execSQL("update Book set price = ? where name = ?", new String[] { "10.99",
"The Da Vinci Code" });
删除数据的方法如下:
db.execSQL("delete from Book where pages > ?", new String[] { "500" });
查询数据的方法如下:
db.rawQuery("select * from Book", null);
可以看到, 除了查询数据的时候调用的是 SQLiteDatabase 的 rawQuery()方法, 其他的操
作都是调用的 execSQL()方法。以上演示的几种方式,执行结果会和前面几小节中我们学习
的 CRUD 操作的结果完全相同,选择使用哪一种方式就看你个人的喜好了
8.使用事务
想象以下场景,比如你正在进行一次转账操作,银行会将转账的金额先从你的账户中扣除,然后再向收款方的账户中添加等量的金额。 看上去好像没什么问题吧?可是, 如果当你账户中的金额刚刚被扣除,这时由于一些异常原因导致对方收款失败,这一部分钱就凭空消失了!当然银行肯定已经充分考虑到了这种情况, 它会保证扣钱和收款的操作要么一起成功, 要么都不会成功,而使用的技术当然就是事务了。
<span style="font-size:14px;">public class MainActivity extends Activity { 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 replaceData = (Button) findViewById(R.id.replace_data); replaceData.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); db.beginTransaction(); // 开启事务 try { db.delete("Book", null, null); if (true) { // 在这里手动抛出一个异常,让事务失败 throw new NullPointerException(); } ContentValues values = new ContentValues(); values.put("name", "Game of Thrones"); 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(); // 结束事务 } } }); } </span><span style="font-size:18px;color:#ff0000;">}</span>8. 2升级数据库的最佳写法
只需要创建一张 Book 表,MyDatabaseHelper 中的代码如下所示:
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)"; public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }不过,几星期之后又有了新需求,这次需要向数据库中再添加一张 Category 表。于是,修改 MyDatabaseHelper 中的代码,如下所示:
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)"; public static final String CREATE_CATEGORY = "create table Category (" + "id integer primary key autoincrement, " + "category_name text, " + "category_code integer)"; public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); db.execSQL(CREATE_CATEGORY); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: db.execSQL(CREATE_CATEGORY); default: } } }是没过多久,新的需求又来了,这次要给 Book 表和 Category 表之间建立关联,需要在 Book 表中添加一个 category_id 的字段。再次修改 MyDatabaseHelper 中的代码,如下所示
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, " + "category_id integer)"; public static final String CREATE_CATEGORY = "create table Category (" + "id integer primary key autoincrement, " + "category_name text, " + "category_code integer)"; public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); db.execSQL(CREATE_CATEGORY); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: db.execSQL(CREATE_CATEGORY); case 2: db.execSQL("alter table Book add column category_id integer"); default: } } }可以看到,首先我们在 Book 表的建表语句中添加了一个 category_id 列,这样当用户直
接安装第三版的程序时,这个新增的列就已经自动添加成功了。然而,如果用户之前已经安
装了某一版本的程序, 现在需要覆盖安装, 就会进入到升级数据库的操作中。 在 onUpgrade()
方法里,我们添加了一个新的 case,如果当前数据库的版本号是 2,就会执行 alter 命令来为
Book 表新增一个 category_id 列。
这里请注意一个非常重要的细节,switch 中每一个 case 的最后都是没有使用 break 的,
为什么要这么做呢?这是为了保证在跨版本升级的时候, 每一次的数据库修改都能被全部执
行到。比如用户当前是从第二版程序升级到第三版程序的,那么 case 2 中的逻辑就会执行。
而如果用户是直接从第一版程序升级到第三版程序的, 那么 case 1 和 case 2 中的逻辑都会执
行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是
最新的,而且表中的数据也完全不会丢失了。
下一篇是关于数据库的封装,更有利于数据的操作。
相关文章推荐
- Android中Strings资源一些冷门用法
- Android 编程下 Touch 事件的分发和消费机制
- Android的文件系统结构
- Android EditText和软键盘绑定的问题
- Android探索之Service全面回顾及总结
- Android——ListView
- Android 双击返回键退出程序的3种写法~
- Android中的四种数据存储方式
- Android 双击返回键退出程序的3种写法~
- Android百度地图SDK:隐藏比例尺,隐藏百度LOGO,隐藏缩放控件
- Android 在任意控件上增加带数字的气泡效果
- Android jni编辑.so库
- android Path 和 PathMeasure 进阶
- WebService---Android中访问WebService接口的方法
- Android数据存储——SharedPreferences及SDCard
- Android frameworks添加资源后编译报错:找不到添加的内部资源 com.android.internal.R
- 小白第一次接触android开发(一)
- 【Android】19、活动的启动模式——standard
- Jenkins+Gradle实现android开发持续集成、打包
- android Spinner 禁止OnItemSelectedListener默认自动调用一次