您的位置:首页 > 移动开发 > Android开发

Android数据库Sqlite完全解析

2016-03-11 17:36 190 查看
不会数据库的司机不是好厨师。今天抽了点时间对Sqlite数据库的使用做了个总结记录。

老规矩,在节目开始之前,首先来一个搞笑段子:

未婚女发现自己怀孕后,第一反应是:“完了,我妈非弄死我不可。”殊不知,她肚子里的孩子也在想:“完了,我妈非弄死我不可。。。”

Android中对数据库的操作主要就是四个:增、删、改、查,加上建表和更新。相比Oracle很多的DDL、DCL操作还是简单很多的。

这篇文章使用User作为例子,记录一下增、删、改、查的使用方法。

首先是Java Bean:User

public class User {
private int id = 0;

private String name = null;

private int age = 0;

public User(){}

public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setAge(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}


然后是数据库操作,就一个类:SqliteOpenHelper

我先把整个类的代码贴出来,再一段段注释。

public class DataBaseHelper extends SQLiteOpenHelper {

private static final String DATABASE_NAME = "test.db";

private static final int VERSION_CODE = 101;

public static final String TABLE = "user";

public static final int _ID = "_id";

public static final int ID = "id";

public static final String NAME = "name";

public static final int AGE = "age";

private SQLiteDatabase db;

private static DataBaseHelper instance = null;

public static DataBaseHelper getInstance(Context context) {
if(instance == null) {
instance = new DataBaseHelper(context);
}
return instance;
}

private DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION_CODE);
db = this.getWritableDatabase();
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE + " ("
+ _ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ ID + " LONG NOT NULL,"
+ NAME + " TEXT NOT NULL,"
+ AGE + " INTEGER NOT NULL);");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
db.execSQL("DROP TABLE " + TABLE + " IF EXISTS");
}
}

public boolean insertUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
ContentValues values = new ContentValues();
values.put(ID, user.getId());
values.put(NAME, user.getName());
values.put(AGE, user.getAge());
long insertRowId = db.insert(TABLE, ID, values);
result = insertRowId != -1;
}
}
return result;
}

public boolean deleteUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
int deleteRows = db.delete(TABLE, ID + "=", new String[]{user.getId()});
result = deleteRows > 0;
}
}
return result;
}

public boolean updateUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
ContentValues values = new ContentValues();
values.put(NAME, user.getName());
values.put(AGE, user.getAge());
int updateRows = db.update(TABLE, values, ID, new String[]{user.getId()});
result = updateRows > 0;
}
}
return result;
}

//查询年龄大于20岁的所有人
public List<User> queryUser(int minAge) {
List<User> users = new ArrayList<User>();
if(minAge > 0) {
synchronized (db) {
Cursor cursor = db.query(TABLE, new String[]{NAME, AGE}, ID + ">?", new String[]{String.valueOf(minAge)}, null, null, String.valueOf(ID));
if(cursor != null && cursor.getCount() > 0) {
while(cursor.moveToNext()) {
User user = new User();
user.setId(cursor.getInt(cursor.getColumnIndex(ID)));
user.setName(cursor.getString(cursor.getColumnIndex(NAME));
user.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
users.add(user);
}
}
if (cursor != null) {
cursor.close();
}
}
}
return user;
}

//分页查询:页面上显示User按年龄排序,每页显示10个,查询第n页的User
public List<User> queryUser(int pageNumber) {
List<User> users = new ArrayList<User>();
if(pageNumber > 0) {
synchronized (db) {
String queryString = "select * from " + TABLE + " order by " + AGE + "limit 10 offset " + (10 * (pageNumber - 1));
Cursor cursor = db.rawQuery(query, null);
if(cursor != null && cursor.getCount() > 0) {
while(cursor.moveToNext()) {
User user = new User();
user.setId(cursor.getInt(cursor.getColumnIndex(ID)));
user.setName(cursor.getString(cursor.getColumnIndex(NAME));
user.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
users.add(user);
}
}
if (cursor != null) {
cursor.close();
}
}
}
}

//批量插入
public boolean insertUsers(List<User> users) {
boolean result = false;
if(users != null && users.size() > 0) {
db.beginTransaction();
for(User user : users) {
insertUser(user);
}
db.setTransactionSuccessful();
db.endTransaction();
}
return result;
}
}


1、常量

private static final String DATABASE_NAME = "test.db";

private static final int VERSION_CODE = 101;

public static final String TABLE = "user";

public static final int _ID = "_id";

public static final int ID = "id";

public static final String NAME = "name";

public static final int AGE = "age";


分别是:

数据库名(在文件系统中的文件名)

数据库版本号(版本更新时有用)

表名(一个数据库可以有多个表)

数据库id(有下划线_,是数据库记录的id,表的主键,自增长,区别User Id)

User Id(User的唯一标识,区别数据库id)

姓名、年龄不解释

2、构造函数

private DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION_CODE);
db = this.getWritableDatabase();
}
指定数据库名和版本号,通过单例模式获取。

3、键表

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE + " ("
+ _ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ ID + " LONG NOT NULL,"
+ NAME + " TEXT NOT NULL,"
+ AGE + " INTEGER NOT NULL);");
}
就是拼接String,调用db.execSQL执行。和敲SQL语句没区别。

4、更新

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
db.execSQL("DROP TABLE " + TABLE + " IF EXISTS");
}
}
为什么系统要提供这个方法呢,是因为随着App的更新,数据库可能会增加新的字段,或者删除字段,导致之前的表不能再使用。

所以需要更新表结构,或者删除表,重新创建。

这里就是判断数据库版本号有更新后,就删除表,重新创建。

5、插入一条User

public boolean insertUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
ContentValues values = new ContentValues();
values.put(ID, user.getId());
values.put(NAME, user.getName());
values.put(AGE, user.getAge());
long insertRowId = db.insert(TABLE, ID, values);
result = insertRowId != -1;
}
}
return result;
}
通过ContentValues把user的属性值保存起来(其实就是一个map),然后调用db.insert(TABLE, ID, values);插入。

第二个参数是什么意思呢?

第二个参数叫做nullColumnHack,是用于当你的values为空时,指定一个列插入空值,以此来保证插入操作不会失败。

既然同样是插入空值,那和values是空有什么区别呢?这个问题要回到原始的SQL语句来理解。

Android调用系统Api实行数据库操作,其实最终都是转化成SQL语句去执行,我们可以想象一下,如果我们不添加nullColumnHack的话,那么我们的sql语句最终的结果将会类似insert into user () values();这语句显然是不允许的。而如果我们添加上nullColumnHack呢,sql将会变成这样,insert into user (nullColumnHack) values(null);哎~这样在语法上就是OK的了。

6、删除一条

public boolean deleteUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
int deleteRows = db.delete(TABLE, ID + "=", new String[]{user.getId()});
result = deleteRows > 0;
}
}
return result;
}
这个比较简单,删除表中指定id的一条,一目了然。

7、更新一条

public boolean updateUser(User user) {
boolean result = false;
if(user != null) {
synchronized (db) {
ContentValues values = new ContentValues();
values.put(NAME, user.getName());
values.put(AGE, user.getAge());
int updateRows = db.update(TABLE, values, ID, new String[]{user.getId()});
result = updateRows > 0;
}
}
return result;
}
这个也挺清晰的,就是指定一个id,找到一条记录,然后更新这条记录为ContentValues的值。

8、查询

//查询年龄大于20岁的所有人
public List<User> queryUser(int minAge) {
List<User> users = new ArrayList<User>();
if(minAge > 0) {
synchronized (db) {
Cursor cursor = db.query(TABLE, new String[]{NAME, AGE}, ID + ">?", new String[]{String.valueOf(minAge)}, null, null, String.valueOf(ID));
if(cursor != null && cursor.getCount() > 0) {
while(cursor.moveToNext()) {
User user = new User();
user.setId(cursor.getInt(cursor.getColumnIndex(ID)));
user.setName(cursor.getString(cursor.getColumnIndex(NAME));
user.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
users.add(user);
}
}
if (cursor != null) {
cursor.close();
}
}
}
return user;
}
代码看起来比较多,但是主要的就db.query这句。

它有7个参数,分别是:表名、查询的列数组、条件、条件参数数组(用于替换条件中的占位符?)、groupby分组、having过滤、orderby排序。

9、分页查询

//分页查询:页面上显示User按年龄排序,每页显示10个,查询第n页的User
public List<User> queryUser(int pageNumber) {
List<User> users = new ArrayList<User>();
if(pageNumber > 0) {
synchronized (db) {
String queryString = "select * from " + TABLE + " order by " + AGE + "limit 10 offset " + (10 * (pageNumber - 1));
Cursor cursor = db.rawQuery(query, null);
if(cursor != null && cursor.getCount() > 0) {
while(cursor.moveToNext()) {
User user = new User();
user.setId(cursor.getInt(cursor.getColumnIndex(ID)));
user.setName(cursor.getString(cursor.getColumnIndex(NAME));
user.setAge(cursor.getInt(cursor.getColumnIndex(AGE)));
users.add(user);
}
}
if (cursor != null) {
cursor.close();
}
}
}
}
对比一下查询,其实就是多了一个limit和offset

limit是指定一组查多少个,offset是指定跳过多少条记录。

比如我们每组查询10个,查询第3组,那limit就是10 ,offset就是10 * (3 - 1)

10、批量插入

public boolean insertUsers(List<User> users) {
boolean result = false;
if(users != null && users.size() > 0) {
db.beginTransaction();
for(User user : users) {
insertUser(user);
}
db.setTransactionSuccessful();
db.endTransaction();
}
return result;
}
看上去和插入一条的差别就是for循环,但是有一个很重要的就是启用了事物。

如果不用事务,每一次插入都是一次事务,耗时较大,for循环200条就就要好几秒。

但是在for循环前db.beginTransaction();

在for循环后db.setTransactionSuccessful();db.endTransaction();

这样,整个for循环就是一个事务,整体速度提升非常大。

以上就是主要的常见的数据库操作,还有一些其它的操作就不细举了。比如索引之类的。

本期节目就到这里,感谢大家的收看,下期再见!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: