本文主要讲述建库建表的流程以及增删改查操作。Android 数据库可以考虑自带的SQLite数据库或各种开源的三方库。本文先讲述系统自带的SQlite数据库的相关操作然后讲述使用WCDB开源库。
第一步、编写继承SQLiteOpenHelper的子类并定义该子类相关的数据库名称、数据库版本信息。如下所示:
public class MyDbHelper extends SQLiteOpenHelper {
private static final String TAG = "MyDbHelper";
//数据库名称
private static final String DATABASE_NAME = "test.db";
//数据库版本信息用于数据库升级
private static int sVersion = 2;
......
}
public static MyDbHelper getInstance(Context context) {
if (null == sDbHelper) {
synchronized (MyDbHelper.class) {
//防止内存泄漏context.getApplicationContext()
sDbHelper = new MyDbHelper(context.getApplicationContext());
}
}
return sDbHelper;
}
private MyDbHelper(Context context) {
super(context, DATABASE_NAME, null, sVersion);
// TODO Auto-generated constructor stub
}
第三步、在onCreate方法中进行建表操作,onCreate方法会在APP第一次安装的时候调用。建表语句如下所示
//建表db.execSQL("CREATE table IF NOT EXISTS "
+ mTableName
+ " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " //
+ DatabaseFiled.COL_NAME
+ " TEXT, " //
+ DatabaseFiled.COL_CARDNUM
+ " TEXT UNIQUE, " //
+ DatabaseFiled.COL_AGE
+ " INTEGER, "//
+ DatabaseFiled.COL_SEX
+ " INTEGER ,"//
+ DatabaseFiled.COL_ADDR
+ " TEXT ); ");//
至此建库建表完成。
由于需求的变化数据库表结构经常会发生变化,但是又要保留以前的数据,这时候我们可以通过采用保留数据升级的方式处理该问题。本文示例在数据表中新增一个字段DatabaseFiled.COL_MARK用来做备注,具体操作如下
第一步、在onUpgrade方法中对数据库版本进行判断(数据库的默认版本好像是1)。只要是老版本低于这次升级的版本的数据库都要执行这段添加字段操作,如下所示:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try{
switch (oldVersion){
case 1:
db.execSQL("ALTER TABLE " + "" + mTableName + " ADD COLUMN "
+ DatabaseFiled.COL_MARK + " TEXT ");
.......
}
这样就能搞定数据库升级的问题?对于非第一安装该APP的用户来说确实可以做到;但是对于第一次安装该APP的用户只会执行onCreate方法从而无法升级到这个字段。所以需要在onCreate方法中的建表语句下增加这条sql语句:
db.execSQL("ALTER TABLE " + "" + mTableName + " ADD COLUMN "
+ DatabaseFiled.COL_MARK + " TEXT ");
这样就实现了数据库保留以前数据,第一次安装的用户也能实现"升级"的数据库升级。
数据库表的操作即CRUD。
第一步,定义数据表操作接口:
public interface UserDao {
boolean addUser(User user);
boolean addUser4Many(List users);
List getUserInfo();
boolean delUser(User user);
boolean modifyUser(User user);
void closeDatabase();
}
第二步,实现该接口
public class UserDaoImpl implements UserDao {
private static final String TAG="UserDaoImpl";
private String mTableName="user";
private MyDbHelper myDbHelper;
public UserDaoImpl(Context ctx){
myDbHelper=MyDbHelper.getInstance(ctx);
myDbHelper.setWriteAheadLoggingEnabled(true);//支持并发
}
//REPLACE INTO 去重 UNIQUE约束
@Override
public boolean addUser(User user) {
SQLiteDatabase database = null;
try{
database = myDbHelper.getWritableDatabase();
if(database.isOpen()){
int sex = user.mSex.equals("M") ? 1 : 0;
String sql="INSERT INTO "+mTableName+"("+ DatabaseFiled.COL_NAME+","+DatabaseFiled.COL_AGE+","+
DatabaseFiled.COL_CARDNUM+","+
DatabaseFiled.COL_SEX+","
+DatabaseFiled.COL_ADDR+")VALUES(?,?,?,?,?)";
database.execSQL(sql,new Object[]{user.mName,Integer.valueOf(user.mAge),user.mCardNum,sex,user.mAddr});
Log.e(TAG,"数据插入成功");
return true;
}
return false;
}catch (Exception e){
e.printStackTrace();
Log.e(TAG,e.toString());
return false;
}
}
//批量操作还可以使用sql预编译进行优化
@Override
public boolean addUser4Many(List users) {
// SQLiteDatabase database = null;
// try{
// database = myDbHelper.getWritableDatabase();
// database.beginTransaction();
// if(database.isOpen()){
// String sql="INSERT INTO "+mTableName+"("+ DatabaseFiled.COL_NAME+","+DatabaseFiled.COL_AGE+","+
// DatabaseFiled.COL_CARDNUM+","+
// DatabaseFiled.COL_SEX+","
// +DatabaseFiled.COL_ADDR+")VALUES(?,?,?,?,?)";
// for(User user:users){
// int sex = user.mSex.equals("M") ? 1 : 0;
// database.execSQL(sql,new Object[]{user.mName,Integer.valueOf(user.mAge),user.mCardNum,sex,user.mAddr});
//
// }
// database.setTransactionSuccessful();
// Log.e(TAG,"数据批量操作完成");
// return true;
// }
//
// return false;
// }catch (Exception e){
// e.printStackTrace();
// Log.e(TAG,e.toString());
// return false;
// }finally {
// if(null!=database){
// database.endTransaction();
// }
// }
//SQL预编译优化
SQLiteDatabase database = null;
try{
database = myDbHelper.getWritableDatabase();
database.beginTransaction();
if(database.isOpen()){
String sql="INSERT INTO "+mTableName+"("+ DatabaseFiled.COL_NAME+","+DatabaseFiled.COL_AGE+","+
DatabaseFiled.COL_CARDNUM+","+
DatabaseFiled.COL_SEX+","
+DatabaseFiled.COL_ADDR+")VALUES(?,?,?,?,?)";
SQLiteStatement statement = database.compileStatement(sql);
for(User user:users){
statement.clearBindings();
if(null!=user.mName) {
statement.bindString(1,user.mName);
}
if(null!=user.mAge) {
statement.bindString(2,user.mAge);
}
if(null!=user.mCardNum) {
statement.bindString(3,user.mCardNum);
}
if(null!=user.mSex) {
statement.bindString(4,user.mSex);
}
if(null!=user.mAddr) {
statement.bindString(5,user.mAddr);
}
statement.executeInsert();
}
database.setTransactionSuccessful();
Log.e(TAG,"sql预编译数据批量操作完成");
return true;
}
return false;
}catch (Exception e){
e.printStackTrace();
Log.e(TAG,e.toString());
return false;
}finally {
if(null!=database){
database.endTransaction();
}
}
}
//查询建索引优化
@Override
public List getUserInfo() {
SQLiteDatabase database = null;
Cursor cursor=null;
try{
database = myDbHelper.getReadableDatabase();
if(database.isOpen()){
String sql="SELECT "+DatabaseFiled.COL_NAME+","+DatabaseFiled.COL_AGE+","+DatabaseFiled.COL_ADDR+","+DatabaseFiled.COL_SEX+" FROM "+mTableName;
cursor= database.rawQuery(sql,null);
User user=null;
ArrayList users=new ArrayList<>();
while (cursor.moveToNext()) {
String name = cursor.getString(cursor
.getColumnIndex(DatabaseFiled.COL_NAME));
String age = cursor.getString(cursor
.getColumnIndex(DatabaseFiled.COL_AGE));
String addr = cursor.getString(cursor
.getColumnIndex(DatabaseFiled.COL_ADDR));
String sex = cursor.getString(cursor
.getColumnIndex(DatabaseFiled.COL_SEX));
user=new User();
user.mName=name;
user.mAge=age;
user.mAddr=addr;
user.mSex=sex;
users.add(user);
user=null;
}
return users;
}
return null;
}catch (Exception e){
e.printStackTrace();
Log.e(TAG,e.toString());
return null;
}finally {
if(null!=cursor){
cursor.close();
}
}
}
@Override
public boolean delUser(User user) {
SQLiteDatabase database = null;
try{
database = myDbHelper.getWritableDatabase();
if(database.isOpen()){
String sql="DELETE FROM "+mTableName +" WHERE "+DatabaseFiled.COL_NAME+"=?";
database.execSQL(sql,new String[]{user.mName});
return true;
}
return false;
}catch (Exception e){
e.printStackTrace();
Log.e(TAG,e.toString());
return false;
}
}
/**
* 根据用户名修改地址和年龄
* @param user
* @return
*/
@Override
public boolean modifyUser(User user) {
SQLiteDatabase database = null;
try{
database = myDbHelper.getWritableDatabase();
if(database.isOpen()){
String sql="UPDATE "+mTableName +" SET "+DatabaseFiled.COL_ADDR+"=?,"+DatabaseFiled.COL_AGE+"=?" +" WHERE "+DatabaseFiled.COL_NAME+"=?";
database.execSQL(sql,new String[]{user.mAddr,user.mAge,user.mName});
Log.e(TAG,"数据修改成功");
return true;
}
return false;
}catch (Exception e){
e.printStackTrace();
Log.e(TAG,e.toString());
return false;
}
}
@Override
public void closeDatabase() {
try {
SQLiteDatabase database = myDbHelper.getWritableDatabase();
if (null != database) {
database.close();
database = null;
}
if (null != myDbHelper) {
myDbHelper.close();
myDbHelper = null;
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG,e.toString());
}
}
}
第三步对外提供方法调用如下所示
public class DataInfoFactory {
private static final String TAG = "DataInfoFactory";
private DataInfoFactory() {
}
public static synchronized UserDao getUserDao(Context context,String type) {
switch (type){
case "user":
if ( null== MyApplication.getInstance().mUserDao) {
MyApplication.getInstance().mUserDao = new UserDaoImpl(context.getApplicationContext());
}
return MyApplication.getInstance().mUserDao;
}
return null;
}
}
1、查询建立索引优化
2、批量插入用事务以及SQL语句预编译见代码。
添加如下依赖
compile 'com.tencent.wcdb:wcdb-android:1.0.2'
并将SQLiteDatabase、SQLiteOpenHelper替换成腾讯的就OK了
其余操作一样。
wcdb地址:https://github.com/Tencent/wcdb
公司项目是个IM系统,客户端需要存储大量的数据,经过自己的大量的压力测试,在低配机上用系统数据库容易爆,但是集成了wcdb后数据不再是问题了,感谢大公司的开源。
本文源码https://github.com/1010540672/MyDbStudy