支付SDK中经常用到的Sqlite数据库

Posted Fastpay快付

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了支付SDK中经常用到的Sqlite数据库相关的知识,希望对你有一定的参考价值。

在Sdk和应用开发过程中,数据库只有Sqlite,其使用起来都是比较方便的(具有轻量级、基于文件、不需要安全以及跨平台的好处),本章节重点讲的不是Sqlite的使用,重点讲述在使用Sqlite数据库时候的存在的一些异常和修复方法以及推荐做法。


  首先来看一段Sqlite的使用步骤:


1、创建数据库,包含创建Sqlite对象和表,升级情况下可以先Drop表,然后再创建,也可执行alter table等Sql语句。


/**
* 创建时传入上下文,数据库名称,版本等数据
*/

SQLiteOpenHelper dbHelper = new SQLiteOpenHelper(context, databaseName, null, dbVer) {
   @Override
   public void onCreate(SQLiteDatabase db) {
       // 执行创建表的Sql语句
       db.execSQL(String.format(CREATE_TABLE_SQL, mTableName));
   }

   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
       // db.execSQL("DROP TABLE IF EXISTS " + mTableName);
// 数据库升级
       db.execSQL(String.format(MODIFY_TABLE_SQL, mTableName));
   }
};
// 获取可写数据对象
mDatabase = dbHelper.getWritableDatabase();


2、数据操作包含insert,update,delete等,方式有两种,使用ContentValues和execSql


try{
   ContentValues cvs = new ContentValues();
   cvs.put(COLUMN_NAME_DATA, info.data);
   cvs.put(COLUMN_NAME_PRIORITY, info.priority);
   cvs.put(COLUMN_NAME_CREATE_TIME, info.createTime);
   cvs.put(COLUMN_NAME_CITY, info.city);
   cvs.put(COLUMN_NAME_REMARK, info.remark);
   long result = mDatabase.insert(mTableName, null, cvs);
   return  result;
} catch (Exception e) {
   // 处理异常
}

 

 

方法二:


//插入数据SQL语句
String sql="insert into city(data,priority,createtime,city,remark) values('GZ','1','2018-07-04 11:34:54', 'GuangZhou','广州又称羊城')";

//执行SQL语句
db.execSQL(sql);

 

 

游标的使用:


Cursor(游标)是SQLite 数据库查询返回的行数集合,Cursor是一个游标接口,提供了遍历查询结果的方法,如移动指针方法move(),获得列值方法getString()等。


如下代码:


SQLiteDatabase db = null;
Cursor cursor = null;
try {
   // 获取可读数据库对象
      db = getReadDB();
      // 查询数据库字段
      cursor = qb.query(db, COLUMNS, where, null, null, null, null);
      // 循环游标
      while (cursor.moveToNext()) {
          // 取数据
          tmpInfo.setCity(cursor.getString(cursor.getColumnIndex(Column.CITY)));

          accountList.add(tmpInfo);
      }
  } catch (Exception e) {

  } finally {
      if (cursor != null) {
          cursor.close();
          cursor = null;
      }
  }


事务的使用:


Transaction(事务)是一个对数据执行工作单元,是以逻辑顺序完成的工作单位或序列。它具备ACID特性,什么叫ACID(原子性【Atomicity】、一致性【Consistency】、隔离性【Isolation】、持久性【Durability】)相信在大学学数据库原理知识的时候,应该对这个都有理解,这里就不细说了。

 

至此数据库的使用已经讲述完毕了,现在我们重点来讲述一下推荐做法和异常。


Tips1:


业务中出现多线程操作写入数据到数据库中时,需要使用事务,以免出现数据同步问题,无论多条一起变更还是一条(大量数据插入除外,大量数据循环插入容易出现notransaction is active异常)。伪代码如下:


beginTransaction();

for execSql->Sql

setTransactionSuccessful();

endTransaction(); // 放在finally语句中

 

 

Tips2:


为了性能及不出错习惯性我们都会打开,操作数据库,而不会显示的去关闭他。在项目中就遇到了这个坑,因为没关闭,造成应用退出前的最后一条数据没办法落盘的问题。


从原来的经验来讲,ContentProvider在数据库操作的时候会有回调通知以方便使用方做更新,如下伪代码:


count =db.delete(FrameStats.TABLE_NAME, selection, selectionArgs);

getContext().getContentResolver().notifyChange(Stats.CONTENT_URI, null);

 

Tips3:


执行SQL语句时,应尽量使用SQLiteDatabase类的insert()update()delete()方法,不要使用execSQL()方法,也不要直接执行字符串作为SQL语句,以免有SQL注入的风险,例如where条件中加入 and 1=1语句。


String sql =String.format("UPDATE %s SET data=%s WHERE id=%s", stat, data,"1 and 1=1");

db.execSQL(sql);

 

Tips4:

SQLite是一个文件,所有的数据都在一个db文件中。

支持数据库级并发,支持线程安全,即允许多个读事务同时运行,同一时刻最多只有一个写事务,读写冲突。

SQLite所有锁实现都是基于文件锁:


在事务开启时上锁,上锁和释放锁同样遵守文件锁协议,在事务提交或回滚时(以及close)才释放锁。

   

常见的异常和解决方案如下:


案例1:


Cursor window allocation of  2048 kb failed(游标内存泄漏异常)

解决方案:在使用数据库的时候忘记释放游标导致内存泄漏,请使用完毕之后手动关闭Cursor(cursor.close),一般推荐放在finally语句中。


案例2:


SqliteDiskIOException:disk I/O error

这种情况一般是由于多线程导致的,因为多线程写数据库,例如有些线程在修改数据,有些线程在删除数据,所以导致了这样的问题

解决方案:在多线程场景下写数据库,做好同步或者独立出一个写数据库的线程,其它线程需要写数据,就发消息给这个写线程。


案例3:


No such table android_metadata

在打开连接的数据时容易出现这个异常,原因是Meta表不存在,解决方案是在Open数据库的函数中加入SQLiteDatabase.NO_LOCALIZED_COLLATORS,同时也应该在OnDestory函数中关闭数据库。

SQLiteDatabase.openDatabase(stPathToDB,null, SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READONLY);


案例4:


WebViewDatabase$1.run(WebViewDatabase.java:1000)异常

在应用或Sdk有使用到WebView组件时,通常容易出现以下问题,因为网页数据缓存也是依赖数据库进行保存(所以在内部存储中可以见到webview.db 和webviewdb.db两个文件)

解决方案:setting.setCacheMode(WebSettings.LOAD_NO_CACHE);

deleteDatabase(“WebView.db”);和deleteDatabase(“WebViewCache.db”);

webView.clearHistory();

webView.clearFormData();

getCacheDir().delete(); 进行缓存数据库的清空。或者采用合适的缓存策略,例如:先判断是否有网络,如果有采用Load_default模式,如果没有Load_cache_else_network.


案例5:


Attempt to re-open an already-closedobject.

频繁操作数据库容易导致这个异常,通常是打开关闭重复等动作。

解决方案:在当前的业务流程中,一直打开数据库,不关闭,在退出的地方再统一对数据库进行关闭。


案例6:


Database is locked.

当我们在不同的线程中创建多个连接时,就会出现这个异常

解决方案:将数据库操作类做成一个单例,并且使用同步的关键字。


以上是关于支付SDK中经常用到的Sqlite数据库的主要内容,如果未能解决你的问题,请参考以下文章

开发中经常用到的特效效果

开发中经常用到的特效效果

开发中经常用到的特效效果

开发中经常用到的特效效果

开发中经常用到的特效效果

总结ASP.NET C#中经常用到的13个JS脚本代码