第六章--绕不开的数据库SQLite
两周就和群里的人有了好大的差距,在绵阳的日子真不好熬,也想把它当作一种磨练,但一边每天去实习,心里总是挂着学习这个的事,心里焦灼,也想向辅导员请假回学校,但是好像在老师眼中,考研学习才是重要的事,其他学习就不重要。喝个鸡汤,加油你可以的。。。。
SQLite数据库
还记得大二时学的数据库,当初还想好好听课,坐在第一排,然而后面就开始在课堂上睡觉。期末考试的时候,复习了几天,记住了一些语句,然后就去参加考试。全学院要学的大课,安排了好多考场,不过是选修,后面去考的人寥寥无几。这样学知识的后果就是学完就忘,并且理解的太浅,或者说没有理解,和学过的数据结构一样。
以上都是些废话。
在android中使用数据库比在java中要简单,最起码过程简单。先来介绍一下SQLite,她是一个嵌入式的数据库引擎,专门适用于资源有限的设备上适量数据的存取。
它有以下的优点:
- 轻量级:使用SQLite数据库不需要向mysql一样安装,启动服务进程,它自己只是一个文件
- 独立:SQLite的核心引擎本身不依赖第三方的软件,有点类似那种绿色软件,不需要软件
- 隔离:我理解的就是它只是一个文件,不依赖其他存在,所以隔离性好
- 跨平台:除了主流操作系统 windows,linux之后,SQLite还支持其它一些不常用的操作系统。
- 多语言接口:SQLite 数据库支持多语言编程接口。
- 安全:SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。
SQLiteDatabase
android提供了SQLiteDatabase代表一个数据库,一旦获得了这个对象就可以用来操作数据库了。首先SQLite有静态方法openDatabase(..)和openOrCreateDatabase(..)方法来打开和创建数据库,android提供了一种更加优雅的方式来创建和更新数据库,SQLiteOpenHelper这个类,所以以下就是从介绍它开始
SQLiteOpenHelper类
创建一个类继承SQLiteOpenHelper
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
*
* Created by W on 2016/8/13.
*/
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String USER_TABLE_NAME = "user";
public static final String USERNAME = "username";
public static final String AGE = "age";
public static final String DATABASE_NAME = "text.db";
public static final int VERSION = 1;
public DatabaseHelper(Context context ) {
//name:数据库的名字,factory:null,版本
super(context, DATABASE_NAME, null, VERSION);
}
//创建数据库
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + USER_TABLE_NAME + " (" + USERNAME + " varchar(20) not null, " + AGE + " varchar(60) not null);");
}
//升级数据库
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//TODO:an database upgrade
}
}
该类的构造器中传入上下文,数据库的名字后缀是.db,null,版本号。下面两个必须重写的方法。onCreate(),用于初次使用软件时生成数据库表,可以添加一些应用使用时的一些初始化数据。onUpgrade(),用于更新软件时升级数据库表结构。以上的代码就创建了一个text的数据库文件。里面有一个表user,有username,age两个字段。
Activity
- 新建一个活动,在onCreate方法中初始化。
DatabaseHelper databaseHelper = new DatabaseHelper(this);
//两种,可读的和可写的.磁盘满了之后,就只能读; 。
mSqLiteDatabase = databaseHelper.getReadableDatabase();
除了gerReadableDatabase(),还有getWriteableDatabase()。两者没有什么区别,只有当磁盘满了之后,就只能读不能写了。当DatabaseHelper对象调用这个方法的时候,如果数据库不存在,android系统会自动生成一个数据库,接着调用onCreate()方法。
- 然后我们在布局文件中写入三个按钮,分别是增删更
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".DatabaseButtonActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add"
android:textAllCaps="false"
android:id="@+id/add_button"/>
<Button
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete"
android:textAllCaps="false"
android:layout_below="@id/add_button"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/delete_button"
android:text="update"
android:textAllCaps="false"
android:id="@+id/update_button"/>
</RelativeLayout>
在activity中初始化按钮绑定监听器。此时如果启动软件,在/data/data/<包名>/Databases文件下就有我们创建的数据库,如图:
这里写图片描述
点开text.db,就有刚刚创建的数据库:
这里写图片描述
这样就是创建好了一个表
数据库操作
- 首先是增,使用insert插入数据,先看代码
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.USERNAME , "haha");
contentValues.put(DatabaseHelper.AGE, "12");
long rawNumber = mSqLiteDatabase.insert(DatabaseHelper.USER_TABLE_NAME, null, contentValues);
if (rawNumber != -1){
Toast.makeText(DatabaseButtonActivity.this,"插入成功" ,Toast.LENGTH_LONG).show();
}
insert()方法里面的参数:
- table:想插入数据库的表名
- nullColumsnHack:代表强行插入null值的数据列的列名。
- valus:代表一行记录的数据
当插入有异常的时候会返回一个long类型的-1值。
- 然后是删:
String whereClauseString = "username=?";
String[] whereArgsString = {"haha"};
mSqLiteDatabase.delete(DatabaseHelper.USER_TABLE_NAME, whereClauseString, whereArgsString);
里面参数的意思就是,在表中username=haha的数据都删除。
- 更新数据:
ContentValues contentValues1 = new ContentValues();
contentValues1.put(DatabaseHelper.AGE, "100");
String whereClauseString1 = "username=?";
String[] whereArgsString1 = {"haha"};
mSqLiteDatabase.update(DatabaseHelper.USER_TABLE_NAME,contentValues1, whereClauseString1, whereArgsString1);
这个和insert有点像,都是先用ContentValus对象把存入的数据写好,然后传到updata的参数里,以上代码的意思就是把user表中username=haha的年纪改成100。
- 最后数据库中的查询操作
在SQLite中查询记录要依靠Cursor(游标),他有一些方法来移动查询结果的记录指针
- boolean moveToFirst():将记录指针移到第一行,成功返回true
- boolean moveToNext():移动到下一行,当只执行一次的时候,相当与moveToFirst
- boolean moveToPosition(int positon):移动到指定行,其实看到这里群里有人提出,moveToNext不是移到了下一个记录了吗?那第一个记录不是没有查询到?然后在这个方法里得到了解释,position默认的值并不是0,而是-1。所以刚开始的指针不是指着第一个记录,而是第一个记录的前面,所以用moveToNext也能查询到第一个记录。
先看代码:
private void QueryDatabase() {
//游标
//query:查询
Cursor cursor = mSqLiteDatabase.query(DatabaseHelper.USER_TABLE_NAME, null, null, null, null, null, null);
if (cursor.moveToFirst()){
int count = cursor.getCount();
for (int i = 0; i < count; i++) {
String userName = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.USERNAME));
String age = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.AGE));
Log.i(DatabaseButtonActivity.class.getSimpleName(), i + ":" + userName + ":" + age);
cursor.moveToNext();
}
}
}
query里面参数有3种形式,以最多那个来解释一下:
- boolean distinct:是否去掉重复的记录
- String table:查询数据的表名
- String[] columns:查询的列名。相当于select后面的关键字
- String whereClause:查询条件子句。where...
- String[] selectionArgs:用于为whereClause子句中的占位符传入参数值。
- String groupBy:控制分组
- String having:分组的过滤
- String orderBy:排序
- String limit:进行分页
query返回的是Cursor对象,getString()取出某一列的数据。
以上就是数据库的基本操作,但是除了创建表的时候,都没有使用过原始的sql语句,据说android为了考虑不太熟悉数据库语句的人,所以提供了这些方法。我看的这本书的作者一直在吐槽这种做法,说作为程序员,数据库操作应该是最基本的素养。其实我觉得吧,我现在用着挺好的哈哈。可以用execSQL()和rawSQL()方法来执行原始的sql语句,而且效率也要高。
最后,相关的io操作还是不要和我一样放在主线程里,毕竟阻塞主线程是大忌。
这些是老师讲的内容,也没怎么理解,比如什么时候使用事务可以达到效率最大化,先留在这。。
如何设计数据库和表
上万条数据如何建表,比如300个城市,每个城市600条数据,对表进行拆表,比如可以先进行排序,再存入
对数据库进行增删改查
- 原始SQL语句效率更高rawQuery,execSQL
- 只检索有用的信息,有用的列,有用的行,越少越好
- 是否排序
- 是否创建索引
事务
- //开始事务,数据库会被锁定
begainTransaction(); - //操作
- ...
- setTransactionSuccessful();
endTransaction()
对象关系映射ORM
- 关系数据库和实体对象进行映射。
- 优点:方便的进行数据库操作
- 缺点:效率比较低,不够灵活