Android数据库存储和访问

    在刚开始接触Android的时候,我甚至都不敢相信,Android系统竟然是内置了数据库的!好吧,是我太孤陋寡闻了。SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百K的内存就足够了,因而特别适合在移动设备上使用。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID(原子性)、一致性、隔离性、持久性事务,所以只要以前使用过其他的关系型数据库,就可以很快的上手SQLite。而SQLite有比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。Android正是把这个功能极为强大的数据库嵌入到了系统中,使得本地持久化的功能有了一次质的飞跃。

    文件存储和SharedPreferences存储毕竟只适用于去保存一些简单的数据和键值对,当需要大量复杂的关系型数据的时候,你会发现以上两种存储方式很难应付得了。比如我们手机的短息程序中可能会有很多会话,每个会话中又包含了很多条信息内容,并且大部分会话还可能各自对应了电话本中的某个联系人。很难想象如何用文件就可以做得到,下面就说一下Andoid中的SQLite数据库到底是如何使用的。

   一。创建数据库

    Android为了让我们能够更加方便的管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单得对数据库进行创建和升级。既然有好东西可你直接用,那我们自然就要尝试一下了。首先要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和 onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中实现创建、升级数据库的逻辑。SQLiteOpenHelper。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据可进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘已满)getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWriteableDatabase()方法则将出现异常。SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收四个参数,第一个参数是Context,第二个参数是数据库名,第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都传入null。第四个参数表示当前数据库版本号,可用于对数据库进行升级操作。

   创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列。SQL语句代码如下:

create table Book (
     id integer primary key autoincrement,
    author text,
    price real,
    pages integer,
    name text
 )
   然后需要在代码中去执行这条SQL语句,才能完成创建表的操作。新建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,
			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()方法中又调用了SQLiteDataBase的execSQL()方法去执行这条建表语句,并弹出一个Toast提示创建成功,这样就可以保证在数据库创建完成的同时还能成功创建Book表。

    现在修改activity_main.xml中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database" />

</LinearLayout>

布局文件很简单,就是加入了一个按钮,用于创建数据库,最后修改MainActivity中的代码,如下所示:

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, 1);
		Button createDatabase = (Button) findViewById(R.id.create_database);
		createDatabase.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				dbHelper.getWritableDatabase();
			}
		});
	}
}

    这里在onCreate()方法中构建了一个MyDatabaseHelper对象,并且通过构造函数的参数名将数据库名指定为BookStore.db,版本号 指定为1,然后在Create database按钮的点击时间里调用了getWriteDatabase()方法,这样当第一次点击Create database按钮时,就会检测到当前程序中并没有BookStore.db这个数据库,于是就会创建该数据库并调用方法,就会弹出一个Toast提示创建成功。再次点击Create database按钮时,会发现此时已经存在数据库了,因此不会再创建一次。现在就可以运行一下代码了,在程序主界面点击Create database按钮,结果如图所示:

   此时BookStore.db数据库和Book表应该都创建成功了,因为当你再次点击Create database按钮时不会再有Toast弹出。可是还是使用File Explore,最多只能看到databases目录下出现了一个BookStore.db文件,Book表是无法通过File Explore看到的。因此这次换一种查看方式,使用adb shell来对数据库和表的创建情况检查。adb shell是Android SDK中自带的一个调试工具,使用这个工具可以直接对连接在电脑上的手机或模拟器进行调试操作。它存放在 sdk 的 platform-tools 目录下,如果想要在命令行中使用这个工具,就需要先把它的路径配置到环境变量里。
如果你使用的是 Windows 系统,可以右击我的电脑→属性→高级→环境变量,然后在系统变量里找到 Path 并点击编辑,将 platform-tools 目录配置进去,如图所示:


配置好了环境变量之后,就可以使用 adb 工具了。打开命令行界面,输入 adb shell,就
会进入到设备的控制台,如图所示:

然后使用 cd 命令进行到/data/data/com.example.databasetest/databases/目录下,并使用
ls  命令查看到该目录里的文件,如图所示:


这个目录下出现了两个数据库文件,的 一个正是我们创建的 BookStore.db,而另一个
BookStore.db-journal 则是为了让数据库能够支持事务而产生的临时日志文件,通常情况下
这个文件的大小都是 0 字节。接下来我们就要借助 sqlite 命令来打开数据库了,只需要键入 sqlite3,后面加上数据库
名即可,如图所示:

这时就已经打开了 BookStore.db 数据库,现在就可以对这个数据库中的表进行管理了。
首先来看一下目前数据库中有哪些表,键入.table 命令,如图所示:

可以看到,此时数据库中有两张表,android_metadata 表是每个数据库中都会自动生成
的,不用管它,而另外一张 Book 表就是我们在 MyDatabaseHelper 中创建的了。这里还可以
通过.schema 命令来查看它们的建表语句,如图所示:

由此证明, BookStore.db 数据库和 Book 表确实已经是创建成功了。 之后键入.exit 或.quit
命令可以退出数据库的编辑,再键入 exit 命令就可以退出设备控制台了。

二。升级数据库

如果你足够细心, 一定会发现 MyDatabaseHelper 中还有一个空方法呢! 没错, onUpgrade()方法是用于对数据库进行升级的, 它在整个数据库的管理工作当中起着非常重要的作用, 可千万不能忽视它哟。目前 DatabaseTest 项中已经有一张 Book 表用于存放书的各种详细数据,如果我们想再添加一张 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)";
	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);
		db.execSQL(CREATE_CATEGORY);
		Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	}
}

看上去好像都挺对的吧, 现在我们重新运行一下程序, 并点击 Create database 按钮, 咦?竟然没有弹出创建成功的提示。当然,你也可以通过 adb 工具到数据库中再去检查一下,这样你会更加地确认,Category  表没有创建功!
其实没有创建成功的原因不难思考, 因为此时 BookStore.db 数据库已经存在了, 之后不管我们怎样点击 Create database 按钮,MyDatabaseHelper 中的 onCreate()方法都不会再次执行,因此新添加的表也就无法得到创建了。
解决这个问题的办法也相当简单,只需要先将程序卸载掉,然后重新运行,这时BookStore.db 数据库已经不存在了,如果再点击 Create database 按钮,MyDatabaseHelper 中的 onCreate()方法就会执行,这时 Category 表就可以创建成功了。不过通过卸载程序的方式来新增一张表毫无疑问是很极端的做法,其实我们只需要巧妙 地 运用SQLiteOpenHelper 的 升 级 功 能 就 可 以 很 轻 松 地 解 决 这 个 问 题 。 修 改MyDatabaseHelper 中的代码,如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {
	@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()方法中执行了两条 DROP 语句,如果发现数据库中已经存在 Book 表或 Category 表了,就将这两张表删除掉,然后再调用 onCreate()方法去重新创建。这里先将已经存在的表删除掉,是因为如果在创建表时发现这张表已经存在了,就会直接报错。接下来的问题就是如何让 onUpgrade()方法能够执行了,还记得 SQLiteOpenHelper 的构造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是 1,现在只要传入一个比 1 大的数,就可以让 onUpgrade()方法得到执行了。修改 MainActivity 中的代码,如下所示:
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 createDatabase = (Button) findViewById(R.id.create_database);
		createDatabase.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				dbHelper.getWritableDatabase();
			}
		});
	}
}

这里将数据库版本号指定为 2,表示我们对数据库进行升级了。现在重新运行程序,并点击 Create database 按钮, 这时就会再次弹出创建成功的提示。 为了验证一下 Category 表是不是已经创建成功了,我们在 adb shell 中打开 BookStore.db 数据库,然后键入.table 命令,如图所示:

接着键入.schema 命令查看一下建表语句,如图所示:

由此可以看出,Category 表已经创建成功了,同时也说明我们的升级功能的确起到了作用。

三。添加数据

   现在你已经掌握了创建和升级数据库的方法, 接下来就该学习一下如何对表中的数据进行操作了。其实我们可以对数据进行的操作也就无非四种,即 CRUD。其中 C  代表添加(Create ) ,R  代表查询(Retrieve ) ,U  代表更新(Update ) ,D  代表删除(Delete) ) 。每一种操作又各自对应了一种 SQL 命令,如果你比较熟悉 SQL 语言的话,一定会知道添加数据时使用 insert,查询数据时使用 select,更新数据时使用 update,删除数据时使用 delete。但是开发者的水平总会是参差不齐的,未必每一个人都能非常熟悉地使用 SQL 语言,因此Android 也是提供了一系列的辅助性方法,使得在 Android 中即使不去编写 SQL 语句,也能轻松完成所有的 CRUD 操作。前面我们已经知道,调用SQLiteOpenHelper 的getReadableDatabase()或getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个SQLiteDatabase 对象,借助这个对象就可以对数据进行 CRUD 操作了。那么我们一个一个功能地看,首先学习一下如何向数据库的表中添加数据吧。SQLiteDatabase 中提供了一个 insert() 方法,这个方法就是专门用于添加数据的。它接收三个参数,第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL, 一般我们用不到这个功能,直接传入 null 即可。第三个参数是一个 ContentValues 对象,它提供了一系列的put()方法重载,用于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。

  修改 activity_main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add data" />

</LinearLayout>

可以看到, 我们在布局文件中又新增了一个按钮, 稍后就会在这个按钮的点击事件里编写添加数据的逻辑。接着修改 MainActivity 中的代码,如下所示:

import android.app.Activity;

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); // 插入第二条数据
			}
		});
	}
}

在添加数据按钮的点击事件里面,我们先获取到了 SQLiteDatabase 对象,然后使用ContentValues 来对要添加的数据进行组装。 如果你比较细心的话应该会发现, 这里只对 Book表里其中四列的数据进行了组装,id  那一列没并没给它赋值。这是因为在前面创建表的时候我们就将 id 列设置为自增长了,它的值会在入库的时候自动生成,所以不需要手动给它赋值了。接下来调用了 insert()方法将数据添加到表当中,注意这里我们实际上添加了两条数据,上述代码中使用 ContentValues 分别组装了两次不同的内容,并调用了两次 insert()方法。

现在可以重新运行一下程序:

点击一下 Add data 按钮,此时两条数据应该都已经添加成功了,不过为了证实一下,我们还是打开 BookStore.db 数据库瞧一瞧。输入 SQL 查询语句 select * from Book,

结果如图所示:

四。更新数据

学习完了如何向表中添加数据,接下来我们看看怎样才能修改表中已有的数据。SQLiteDatabase 中也是提供了一个非常好用的 update()方法用于对数据进行更新,这个方法
接收四个参数,第一个参数和 insert()方法一样,也是表名,在这里指定去 更新哪张表里的数据。第二个参数是 ContentValues 对象,要把更新数据在这里组装进去。第三、第四个参数用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。那么接下来我们仍然是在DatabaseTest项目的基础上修改, 看一下更新数据的具体用法。比如说刚才添加到数据库里的第一本书,由于过了畅销季,卖得不是很火了,现在需要通过降低价格的方式来吸引更多的顾客, 我们应该怎么操作呢?首先修改 activity_main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update data" />

</LinearLayout>

布局文件中的代码就已经非常简单了, 就是添加了一个用于更新数据的按钮。 然后修改MainActivity 中的代码,如下所示:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

    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" });
        }
     });
        }
}

这里在更新数据按钮的点击事件里面构建了一个 ContentValues 对象,并且只给它指定了一组数据, 说明我们只是想把价格这一列的数据更新成 10.99。 然后调用了 SQLiteDatabase的 update()方法去执行具体的更新操作,可以看到,这里使用了第三、第四个参数来指定具体更新哪几行。第三个参数对应的是 SQL 语句的 where 部分,表示去更新所有 name 等于?的行,而?是一个占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容。因此上述代码想表达的意图就是,将名字是 The Da Vinci Code的这本书的价格改成 10.99。

现在重新运行一下程序:

点击一下 Update data 按钮后,再次输入查询语句查看表中的数据情况,


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值