「优化」

优化了数据库存储
This commit is contained in:
董宏宇
2020-08-03 20:06:51 +08:00
parent 156f5f21a2
commit ff3ad48fc2
7 changed files with 74 additions and 488 deletions

View File

@@ -1,433 +0,0 @@
package com.mogo.utils.sqlite
import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import com.mogo.utils.logger.Logger
import com.mogo.utils.sqlite.annotation.DbField
import com.mogo.utils.sqlite.annotation.DbTable
import java.lang.reflect.Field
import java.util.*
/**
* <p>数据类操作实现</p>
*Created by donghongyu on 2019/9/6.
*/
//T必须指明上界是Any且不为null下面会用到反射获取对象实例默认是Any?
open class BaseDao<T : Any> : IBaseDao<T> {
private val TAG = "BaseDao"
//数据库操作的引用
private var sqLiteDatabase: SQLiteDatabase? = null
//要操作的数据实体的引用
private var entityClass: Class<T>? = null
//要操作的数据表名称
private var tableName: String? = null
//记录数据表是否存在
private var isInit = false
//因为反射会消耗时间,这里使用缓存,进行性能优化
//缓存空间key-字段名,标注的自定义注解 value-成员变量)
private var cacheField: HashMap<String, Field>? = null
override fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean {
this.sqLiteDatabase = sqLiteDatabase
this.entityClass = entityClass
//自动建表(只创建一次)
if (!isInit) {
//获取表名
tableName = entityClass.getAnnotation(DbTable::class.java).tableName
//如果数据库没有建立连接跳出操作防止异常信息
if (!sqLiteDatabase.isOpen) {
return false
}
//执行Sql进行自动建表
val createTableSql = getCreateTableSql()
Logger.d(TAG, "执行SQL$createTableSql")
sqLiteDatabase.execSQL(createTableSql)
//初始化缓存空间
cacheField = HashMap()
initCacheField()
//标记已经创建过数据表
isInit = true
}
return isInit
}
/**
* 初始化字段缓存
*/
private fun initCacheField() {
//1.取到所有的列名(查询一个空表获取表结构,不影响性能)
if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
val sqlQuery = "select * from $tableName limit 1,0"
val cursor = sqLiteDatabase!!.rawQuery(sqlQuery, null)
//获取所有的列名
val columnNames = cursor.columnNames
//关闭资源
cursor.close()
//2.取所有成员名
val columnFields = entityClass!!.declaredFields
//3.通过两层循环,进行对应关系建立
columnNames.forEach ColumnFor@{ columnName ->
columnFields.forEach FieldFor@{ columnField ->
if (columnName == columnField.getAnnotation(DbField::class.java).fieldName) {
columnField.isAccessible = true
cacheField!![columnName] = columnField
}
return@FieldFor
}
}
}
}
/**
* 拼装创建数据表的SQL语句
*/
private fun getCreateTableSql(): String? {
//create table if not exists tb_name(_id integer,name varchar2(20))
val sqlCreateTable = StringBuffer()
sqlCreateTable.append("create table if not exists ")
sqlCreateTable.append("$tableName (")
//反射获取所有的数据对象内的成员变量
val fields = entityClass!!.declaredFields
fields.forEachIndexed { index, field ->
//字段名称
val columnName = field.getAnnotation(DbField::class.java).fieldName
//获取成员变量数据类型
when (val fieldType = field.type) {
java.lang.String::class.java -> {
sqlCreateTable.append("$columnName TEXT,")
}
java.lang.Integer::class.java -> {
sqlCreateTable.append("$columnName INTEGER,")
}
java.lang.Long::class.java -> {
sqlCreateTable.append("$columnName BIGINT,")
}
java.lang.Double::class.java -> {
sqlCreateTable.append("$columnName DOUBLE,")
}
ByteArray::class.java -> {
sqlCreateTable.append("$columnName BLOB,")
}
else -> {
//未知类型
throw UnsupportedOperationException("未定义的数据类型fieldName= $columnName fieldType= $fieldType")
}
}
if (index == fields.size - 1) {
if (sqlCreateTable.endsWith(","))
sqlCreateTable.deleteCharAt(sqlCreateTable.length - 1)
}
}
sqlCreateTable.append(")")
return sqlCreateTable.toString()
}
/**
* 插入数据
*/
override fun insert(entity: T): Long {
//1、准备好ContentValues中的数据
//2、设置插入的内容
val values: ContentValues = getContentValuesForInsert(entity)
//3、执行插入
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
sqLiteDatabase!!.insert(tableName, null, values)
} else {
-1
}
}
/**
* 删除数据
*/
override fun delete(where: T): Int {
val condition = Condition(getContentValuesForQuery(where))
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
//受影响行数
sqLiteDatabase!!
.delete(
tableName,
condition.getWhereCause(),
condition.getWhereArgs()
)
} else {
-1
}
}
/**
* 更新数据
*/
override fun update(where: T, newEntity: T): Int {
val condition = Condition(getContentValuesForQuery(where))
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
//受影响行数
sqLiteDatabase!!
.update(
tableName,
getContentValuesForInsert(newEntity),
condition.getWhereCause(),
condition.getWhereArgs()
)
} else {
-1
}
}
/**
* 查询数据
* @param where 查询条件对象,同时也用来初始化对象使用
*/
override fun query(where: T): MutableList<T> {
return query(where, null, null, null)
}
/**
* 查询数据
* @param where 查询条件对象
* @param orderBy 排序规则
* @param startIndex 开始的位置
* @param limit 限制查询得到的数据个数
*/
fun query(where: T, orderBy: String?, startIndex: Int?, limit: Int?): MutableList<T> {
//拼接分页语句
var limitString: String? = null
if (startIndex != null && limit != null) {
limitString = "$startIndex,$limit"
}
val condition = Condition(getContentValuesForQuery(where))
var cursor: Cursor? = null
//定义查询结果
val result = mutableListOf<T>()
if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
try {
//查询数据库
cursor = sqLiteDatabase!!
.query(
tableName,
null,
condition.getWhereCause(),
condition.getWhereArgs(),
null,
null,
orderBy,
limitString
)
//将查到结果添加到返回集合中
result.addAll(getQueryResult(cursor, where))
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
}
Logger.d(TAG, "查询结果:" + result.size + "")
return result
}
/**
* 获取查询使用的ContentValues
*/
private fun getContentValuesForQuery(entity: T): ContentValues {
val contentValues = ContentValues()
try {
cacheField!!.forEach {
if (it.value.get(entity) == null) {
return@forEach
}
contentValues.put(it.key, it.value.get(entity).toString())
}
} catch (e: IllegalAccessError) {
e.printStackTrace()
}
return contentValues
}
/**
* 条件拼接
*/
class Condition(whereContent: ContentValues) {
/**
* 条件拼接
* _id=?&&name=?
*/
private var whereCause: String? = null
private var whereArgs: Array<String>? = null
//根据传入的contentValues转换成查询条件
init {
//记录后面填充到查询语句“?”上的数据参数
val argList = mutableListOf<String>()
//拼接查询语句
val whereCaseSb = StringBuilder()
/**
* 是为了链接下面的查询条件条件,也或者是替换没有查询条件的语句。
* 比如要把检索条件作为一个参数传递给SQL
* 那么当这个检索语句不存在的话就可以给它赋值为1=1.
* 这样就避免了SQL出错也就可以把加条件的SQL和不加条件的SQL合二为一。
*/
whereCaseSb.append(" 1=1 ")
val keys = whereContent.keySet()
val iterator = keys.iterator()
//因为使用了“1=1”所以即便是这里没有任何数据拼接也是可以正常
while (iterator.hasNext()) {
val key = iterator.next() as String
val valueObject = whereContent.get(key)
if (valueObject != null) {
val value = valueObject as String
//拼接查询条件语句
//1:1 and _id=? and name=?
whereCaseSb.append(" and $key =?")
//记录对应的value
argList.add(value)
}
}
//集合转成数组
this.whereArgs = argList.toTypedArray()
this.whereCause = whereCaseSb.toString()
}
fun getWhereCause(): String {
return this.whereCause!!
}
fun getWhereArgs(): Array<String> {
return this.whereArgs!!
}
}
/**
* 获取查询db结果
*/
private fun getQueryResult(cursor: Cursor, where: T): MutableList<T> {
//定义查询结果
val result = mutableListOf<T>()
//Cursor从头读到尾
//游标从头读到尾
cursor.moveToFirst()
//移动游标获取下一行数据
while (!cursor.isAfterLast) {
//通过反射构建一个查询结果对象
val item = where.javaClass.newInstance()
//拿到缓存的当前数据对象的成员变量与数据库的键值关系
val fieldIterator = cacheField!!.entries.iterator()
fieldIterator.forEach IteratorFor@{
//获取数据库字段名称
val columnName = it.key
//数据库字段名对应的数据对象的成员变量
val field = it.value
//获取指定列名对应的索引
val columnIndex = cursor.getColumnIndex(columnName)
//获取成员变量数据类型
val fieldType = field.type
if (columnIndex != -1) {
when (fieldType) {
java.lang.String::class.java -> {
field.set(item, cursor.getString(columnIndex))
}
java.lang.Integer::class.java -> {
field.set(item, cursor.getInt(columnIndex))
}
java.lang.Long::class.java -> {
field.set(item, cursor.getLong(columnIndex))
}
java.lang.Double::class.java -> {
field.set(item, cursor.getDouble(columnIndex))
}
ByteArray::class.java -> {
field.set(item, cursor.getBlob(columnIndex))
}
else -> {
//未知类型
throw UnsupportedOperationException("未定义的数据类型columnName= $columnName fieldType= $fieldType")
}
}
}
}
//添加到结果集
result.add(item)
//移动到下一个位置
cursor.moveToNext()
}
cursor.close()
return result
}
/**
* 获取插入使用的ContentValues
*/
private fun getContentValuesForInsert(entity: T): ContentValues {
val contentValues = ContentValues()
val fieldIterator = cacheField!!.entries.iterator()
fieldIterator.forEach IteratorFor@{
try {
//获取变量的值
val valueObject = it.value.get(entity) ?: return@IteratorFor
//获取列名
val columnName = it.key
//获取成员变量数据类型
val fieldType = it.value.type
when (fieldType) {
java.lang.String::class.java -> {
contentValues.put(columnName, valueObject as String)
}
java.lang.Integer::class.java -> {
contentValues.put(columnName, valueObject as Int)
}
java.lang.Long::class.java -> {
contentValues.put(columnName, valueObject as Long)
}
java.lang.Double::class.java -> {
contentValues.put(columnName, valueObject as Double)
}
ByteArray::class.java -> {
contentValues.put(columnName, valueObject as ByteArray)
}
else -> {
//未知类型
throw UnsupportedOperationException("未定义的数据类型columnName= $columnName fieldType= $fieldType")
}
}
} catch (e: IllegalArgumentException) {
e.printStackTrace()
}
}
Logger.d(TAG, "contentValues:$contentValues")
return contentValues
}
}

View File

@@ -1,35 +0,0 @@
package com.mogo.utils.sqlite
import android.database.sqlite.SQLiteDatabase
/**
* <p>操作SQLite数据库的顶层接口</p>
* Created by donghongyu on 2019/9/6.
*/
interface IBaseDao<T> {
/**
* 初始化数据库连接
*/
fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean
/**
* 将 [entity] 进行数据插入
*/
fun insert(entity: T): Long
/**
* 根据条件 [where] 进行数据删除
*/
fun delete(where: T): Int
/**
* 根据条件 [where] 进行数据更新,如果[where]==只初始化不赋值 则代表删除所有数据
*/
fun update(where: T, newEntity: T): Int
/**
* 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
*/
fun query(where: T): MutableList<T>
}

View File

@@ -23,7 +23,7 @@ import java.util.Set;
* @param <T>
* @author donghongyu
*/
public class SQLBaseDao<T> implements IBaseDao<T> {
public class SQLBaseDao<T> implements SQLIDao<T> {
private String TAG = "SQLBaseDao";
//数据库操作的引用
@@ -139,6 +139,18 @@ public class SQLBaseDao<T> implements IBaseDao<T> {
return query(where, null, null, null);
}
/**
* 查询数据
*
* @param where 查询条件对象,同时也用来初始化对象使用
*/
@NotNull
@Override
public List<T> query(T where, String orderBy) {
return query(where, orderBy, null, null);
}
/**
* 查询数据
*

View File

@@ -10,14 +10,14 @@ import com.mogo.utils.sqlite.proxy.BaseDaoProxyLog
* <p>数据库处理工厂</p>
* Created by donghongyu on 2019/9/6.
*/
open class BaseDaoFactory {
open class SQLDaoFactory {
//默认数据库名称
private var dbName = "MoGoSQLite.db"
companion object {
//单利工厂
private var baseDaoFactory: BaseDaoFactory? = null
private var sqlDaoFactory: SQLDaoFactory? = null
//数据库存储路径
private lateinit var sqLiteDatabasePath: String
@@ -25,21 +25,21 @@ open class BaseDaoFactory {
//数据库操作类
private var sqLiteDatabase: SQLiteDatabase? = null
fun getInstance(): BaseDaoFactory {
if (baseDaoFactory == null) {
synchronized(BaseDaoFactory::class.java) {
if (baseDaoFactory == null) {
baseDaoFactory = BaseDaoFactory()
fun getInstance(): SQLDaoFactory {
if (sqlDaoFactory == null) {
synchronized(SQLDaoFactory::class.java) {
if (sqlDaoFactory == null) {
sqlDaoFactory = SQLDaoFactory()
}
}
}
return baseDaoFactory!!
return sqlDaoFactory!!
}
}
//获取数据库操作对象
fun <T : Any> getBaseDao(context: Context, entityClass: Class<T>): IBaseDao<T>? {
var baseDao: IBaseDao<T>? = null
fun <T : Any> getBaseDao(context: Context, entityClass: Class<T>): SQLIDao<T>? {
var baseDao: SQLIDao<T>? = null
try {
//获取数据库名称,如果没有设置则使用默认名称
@@ -56,7 +56,7 @@ open class BaseDaoFactory {
// baseDao = BaseDaoProxyShow().bind(BaseDaoProxyLog().bind(BaseDao<T>())) as IBaseDao<T>
// baseDao = BaseDaoProxyLog().bind(SQLBaseDao<T>()) as IBaseDao<T>
// baseDao = BaseDao<T>()
baseDao = BaseDaoProxyLog().bind(BaseDao<T>()) as IBaseDao<T>
baseDao = BaseDaoProxyLog().bind(SQLBaseDao<T>()) as SQLIDao<T>
baseDao.init(sqLiteDatabase!!, entityClass)
} catch (e: Exception) {

View File

@@ -0,0 +1,42 @@
package com.mogo.utils.sqlite;
import android.database.sqlite.SQLiteDatabase;
import java.util.List;
/**
* 数据库操作接口
*
* @author donghongyu
*/
public interface SQLIDao<T> {
/**
* 初始化数据库连接
*/
boolean init(SQLiteDatabase sqLiteDatabase, Class<T> entityClass);
/**
* 将 [entity] 进行数据插入
*/
long insert(T entity);
/**
* 根据条件 [where] 进行数据删除
*/
int delete(T where);
/**
* 根据条件 [where] 进行数据更新,如果[where]==只初始化不赋值 则代表删除所有数据
*/
int update(T where, T newEntity);
/**
* 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
*/
List<T> query(T where);
/**
* 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
*/
List<T> query(T where, String orderBy);
}

View File

@@ -2,13 +2,13 @@ package com.mogo.utils.sqlite.proxy
import android.database.sqlite.SQLiteDatabase
import android.util.Log
import com.mogo.utils.sqlite.IBaseDao
import com.mogo.utils.sqlite.SQLIDao
/**
* <p>静态代理数据库操作类,用来记录日志</P>
* Created by donghongyu on 2019/9/6.
*/
class BaseDaoProxy<T>(var iBaseDao: IBaseDao<T>) : IBaseDao<T> by iBaseDao {
class BaseDaoProxy<T>(var iBaseDao: SQLIDao<T>) : SQLIDao<T> by iBaseDao {
override fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean {
Log.i("数据库代理", "初始化数据库连接……")
val isInitSuccess = iBaseDao.init(sqLiteDatabase, entityClass)

View File

@@ -3,8 +3,8 @@ package com.mogo.module.v2x.utils;
import com.mogo.module.common.entity.V2XHistoryScenarioData;
import com.mogo.module.v2x.V2XConst;
import com.mogo.utils.logger.Logger;
import com.mogo.utils.sqlite.BaseDaoFactory;
import com.mogo.utils.sqlite.IBaseDao;
import com.mogo.utils.sqlite.SQLDaoFactory;
import com.mogo.utils.sqlite.SQLIDao;
import java.util.List;
@@ -17,16 +17,16 @@ public class V2XSQLiteUtils {
/**
* 场景数据管理
*/
private static IBaseDao<V2XHistoryScenarioData> mScenarioHistoryDao;
private static SQLIDao<V2XHistoryScenarioData> mScenarioHistoryDao;
/**
* 场景数据管理
*/
public static IBaseDao<V2XHistoryScenarioData> getScenarioHistoryDao() {
public static SQLIDao<V2XHistoryScenarioData> getScenarioHistoryDao() {
if (mScenarioHistoryDao == null) {
synchronized (V2XSQLiteUtils.class) {
if (mScenarioHistoryDao == null) {
mScenarioHistoryDao = BaseDaoFactory.Companion.getInstance()
mScenarioHistoryDao = SQLDaoFactory.Companion.getInstance()
.getBaseDao(V2XUtils.getApp(), V2XHistoryScenarioData.class);
}
}
@@ -58,7 +58,7 @@ public class V2XSQLiteUtils {
* 查询当天的V2X数据
*/
public static List<V2XHistoryScenarioData> getScenarioHistoryData() {
return getScenarioHistoryDao().query(new V2XHistoryScenarioData());
return getScenarioHistoryDao().query(new V2XHistoryScenarioData(), "triggerTime DESC");
}
}