package com.m.support.sqlite; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.text.TextUtils; import com.m.common.context.GlobalContext; import com.m.common.settings.Setting; import com.m.common.settings.SettingUtility; import com.m.common.utils.Logger; import com.m.common.utils.SystemUtility; import com.m.support.sqlite.property.Extra; import com.m.support.sqlite.property.Property; import com.m.support.sqlite.property.TableInfo; import com.m.support.sqlite.util.ClassUtils; import com.m.support.sqlite.util.FieldUtils; import com.m.support.sqlite.util.SqlBuilder; /** * sqlite操作帮助类,暂时不支持版本升级 * * @author wangdan */ public class SqliteUtility { public static final String TAG = "SqliteUtility"; private static HashMap<String, SqliteUtility> sqliteHelperMap; static { sqliteHelperMap = new HashMap<String, SqliteUtility>(); } private SQLiteDatabase db; private TableInfo tableInfoUtils; private SqliteUtility(SQLiteDatabase db) { this.db = db; tableInfoUtils = new TableInfo(); } public static void remve(String key) { SqliteUtility sqliteUtility = sqliteHelperMap.get(key); if (sqliteUtility != null) { sqliteUtility.db.close(); } sqliteHelperMap.remove(key); } public static void deleteDB(String dbName) { try { boolean bol = SQLiteDatabase.deleteDatabase(GlobalContext.getInstance().getDatabasePath(dbName)); Logger.w(TAG, String.format("删除DB[dbName = %s],结果: %s", dbName, String.valueOf(bol))); } catch (Exception e) { e.printStackTrace(); } } public static void deleteSdcardDB(String dbName) { try { boolean bol = SQLiteDatabase.deleteDatabase(new File(getDBPath(dbName))); Logger.w(TAG, String.format("删除Sdcard DB[dbName = %s],结果: %s", dbName, String.valueOf(bol))); } catch (Exception e) { e.printStackTrace(); } } /** * 2014-06-19:新增对sdcard和程序内部目录的选择 * * @param key * @param dbName * @return */ public static SqliteUtility getInstanceInSdcard(String key, String dbName) { SqliteUtility sqliteUtility = sqliteHelperMap.get(key); if (sqliteUtility == null) { sqliteUtility = new SqliteUtility(openSdcardDb(dbName)); sqliteHelperMap.put(key, sqliteUtility); } return sqliteUtility; } /** * 2014-06-09:新增多个库的支持 * * @param key * @param dbName * @return */ public static SqliteUtility getInstanceInApp(String key, String dbName) { SqliteUtility sqliteUtility = sqliteHelperMap.get(key); if (sqliteUtility == null) { sqliteUtility = new SqliteUtility(new SqliteDbHelper(dbName).getWritableDatabase()); sqliteHelperMap.put(key, sqliteUtility); } return sqliteUtility; } public static SqliteUtility getInstance() { SqliteUtility sqliteUtility = sqliteHelperMap.get("default"); if (sqliteUtility == null) { String dbType = SettingUtility.getStringSetting("db_type"); if ("sdcard".equals(dbType)) try { sqliteUtility = new SqliteUtility(openSdcardDb()); } catch (Exception e) { sqliteUtility = new SqliteUtility(new SqliteDbHelper(SettingUtility.getStringSetting("db_name")).getWritableDatabase()); } else if ("app".equals(dbType)) sqliteUtility = new SqliteUtility(new SqliteDbHelper(SettingUtility.getStringSetting("db_name")).getWritableDatabase()); else throw new RuntimeException("db_type not setting"); sqliteHelperMap.put("default", sqliteUtility); } return sqliteUtility; } private Object[] getSelectionAndArgs(String idColumnName, Extra extra) { String[] argArr = new String[10]; String[] valueArr = new String[10]; if (extra != null) { int index = 0; int indexForValue = 0; if (!TextUtils.isEmpty(idColumnName) && !TextUtils.isEmpty(extra.getId())) { argArr[index++] = idColumnName; valueArr[indexForValue++] = extra.getId(); } if (!TextUtils.isEmpty(extra.getOwner())) { argArr[index++] = FieldUtils.OWNER; valueArr[indexForValue++] = extra.getOwner(); } if (!TextUtils.isEmpty(extra.getKey())) { argArr[index++] = FieldUtils.KEY; valueArr[indexForValue++] = extra.getKey(); } } StringBuffer sbForArgs = new StringBuffer(); List<String> valueList = new ArrayList<String>(); for (int i = 0; i < argArr.length; i++) { String arg = argArr[i]; String value = valueArr[i]; if (!TextUtils.isEmpty(arg) && !TextUtils.isEmpty(value)) { sbForArgs.append(" ").append(arg).append(" = ? "); sbForArgs.append("and"); valueList.add(value); } } String selection = sbForArgs.toString(); if (!TextUtils.isEmpty(selection)) { selection = selection.substring(0, selection.length() - 3); String[] selectionArgs = new String[valueList.size()]; for (int i = 0; i < selectionArgs.length; i++) selectionArgs[i] = valueList.get(i); return new Object[] { selection, selectionArgs }; } return null; } public Cursor rawQuery(Class<?> clazz, String sql, String[] selectionArgs) { checkTableExist(clazz); return getRd().rawQuery(sql, selectionArgs); } public Cursor query(Class<?> clazz, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { checkTableExist(clazz); return getRd().query(ClassUtils.getTableName(clazz), columns, selection, selectionArgs, groupBy, having, orderBy, limit); } /** * 插入一个实体,如果已经存在,则更新 * * @param extra * @param entity */ public <T> void insert(Extra extra, T entity) { insert(extra, entity, true); } public <T> void insert(Extra extra, T entity, boolean autoUpdate) { checkTableExist(entity.getClass()); try { Field idField = ClassUtils.getPrimaryKeyField(entity.getClass()); idField.setAccessible(true); String idColName = FieldUtils.getColumnNameByField(idField); String selection = null; String[] selectionArgs = null; if (extra == null) extra = new Extra(); extra.setId(idField.get(entity).toString()); Object[] o = getSelectionAndArgs(idColName, extra); if (o != null) { selection = o[0].toString(); selectionArgs = (String[]) o[1]; } int flag = 0; if (autoUpdate) { flag = getWd() .update(ClassUtils.getTableName(entity.getClass()), ClassUtils.getUpdateContentValues(tableInfoUtils, entity), selection, selectionArgs); if (flag > 0) Logger.d(TAG, String.format(" 更新 , id = %s, key = %s", extra.getId(), extra.getKey() + "")); } else { Cursor cursor = getRd().query(ClassUtils.getTableName(entity.getClass()), null, selection, selectionArgs, null, null, null); if (cursor.moveToFirst()) { flag = 1; Logger.d(TAG, String.format(" 已存在,不更新 , id = %s, key = %s", extra.getId(), extra.getKey())); } } if (flag > 0) { } else { Logger.d(TAG, String.format(" 插入, id = %s, key = %s", extra.getId(), extra.getKey() + "")); getWd().insert(ClassUtils.getTableName(entity.getClass()), idColName, ClassUtils.getContentValues(tableInfoUtils, extra, entity)); } } catch (Exception e) { e.printStackTrace(); } } /** * 2014-08-21,新增批量插入数据 * * @param extra * @param entities * @param autoUpdate */ public <T> void insertBatchList(List<SqliteBatchBean<T>> batch, boolean autoUpdate) { if (batch != null && batch.size() > 0) { getRd().beginTransaction(); long time = System.currentTimeMillis(); Logger.i(TAG, "*******************************************"); Logger.i(TAG, "begin insert List"); int count = 0; try { for (SqliteBatchBean<T> bean : batch) { Extra extra = bean.extra; List<T> entities = bean.list; if (entities == null || entities.size() == 0) continue; count += entities.size(); Class<?> clazz = entities.get(0).getClass(); checkTableExist(clazz); for (T entity : entities) { if (extra == null) extra = new Extra(); // id属性 Field idField = ClassUtils.getPrimaryKeyField(entity.getClass()); idField.setAccessible(true); String idColName = FieldUtils.getColumnNameByField(idField); String selection = null; String[] selectionArgs = null; extra.setId(idField.get(entity).toString()); Object[] o = getSelectionAndArgs(idColName, extra); if (o != null) { selection = o[0].toString(); selectionArgs = (String[]) o[1]; } int flag = 0; if (selection != null && selectionArgs != null) { if (autoUpdate) { flag = getWd().update(ClassUtils.getTableName(entity.getClass()), ClassUtils.getUpdateContentValues(tableInfoUtils, entity), selection, selectionArgs); if (flag > 0) Logger.v(TAG, String.format(" 更新已存在, id = %s, key = %s", extra.getId(), extra.getKey() + "")); } else { Cursor cursor = getRd().query(ClassUtils.getTableName(entity.getClass()), null, selection, selectionArgs, null, null, null); if (cursor.moveToFirst()) { flag = 1; Logger.v(TAG, String.format(" 已存在,不更新, id = %s, key = %s", extra.getId(), extra.getKey() + "")); } } } if (flag == 0) { Logger.v(TAG, String.format(" 插入, id = %s, key = %s", extra.getId(), extra.getKey() + "")); getRd().insert(ClassUtils.getTableName(entity.getClass()), idColName, ClassUtils.getContentValues(tableInfoUtils, extra, entity)); } } } } catch (Exception e) { e.printStackTrace(); } getRd().setTransactionSuccessful(); getRd().endTransaction(); Logger.i(TAG, "end insert List"); Logger.i(TAG, "*******************************************"); Logger.w(TAG, String.format("插入%d条数据,共耗时%s秒", count, String.valueOf((System.currentTimeMillis() - time) / 1000))); } } /** * 2014-08-21,新增批量插入数据 * * @param extra * @param entities * @param autoUpdate */ public <T> void insertList(Extra extra, List<T> entities, boolean autoUpdate) { SqliteBatchBean<T> batch = new SqliteBatchBean<T>(); batch.extra = extra; batch.list = entities; List<SqliteBatchBean<T>> batchList = new ArrayList<SqliteUtility.SqliteBatchBean<T>>(); batchList.add(batch); insertBatchList(batchList, autoUpdate); } public <T> void insertList(Extra extra, List<T> entities) { insertList(extra, entities, true); } /** * @param clazz * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @param limit * @return */ public <T> List<T> selectAll(Class<T> clazz, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { checkTableExist(clazz); List<T> result = new ArrayList<T>(); SQLiteDatabase db = getRd(); TableInfo tableInfo = tableInfoUtils.get(clazz); Field idField = tableInfo.getId().getField(); Logger.d( TAG, String.format("begin read List, table = %s", ClassUtils.getTableName(clazz))); if (selection != null) Logger.i(TAG, String.format("selection = %s", selection)); if (selectionArgs != null) for (String arg : selectionArgs) Logger.i(TAG, arg); Cursor cursor = db.query(ClassUtils.getTableName(clazz), null, selection, selectionArgs, groupBy, having, orderBy, limit); if (cursor.moveToFirst()) { do { try { T t = clazz.newInstance(); // 设置主键 idField.setAccessible(true); setFieldValue(t, idField, cursor.getString(cursor.getColumnIndex(FieldUtils.getColumnNameByField(idField)))); // idField.set(t, FieldUtils.json2Value(cursor.getString(cursor.getColumnIndex(FieldUtils.getColumnNameByField(idField))), idField)); // 设置各属性 if (tableInfo.propertyMap.size() > 0) { Set<String> keySet = tableInfo.propertyMap.keySet(); for (String key : keySet) { Property property = tableInfo.propertyMap.get(key); Field field = property.getField(); field.setAccessible(true); int colIndex = cursor.getColumnIndex(FieldUtils.getColumnNameByField(field)); if (colIndex == -1) continue; String value = cursor.getString(colIndex); setFieldValue(t, field, value); } } // Logger.v(TAG, String.format("load data --->%s", Logger.toJson(t))); result.add(t); } catch (Exception e) { e.printStackTrace(); } } while (cursor.moveToNext()); Logger.d(TAG, "read List size = " + result.size()); Logger.d(TAG, "end read List"); } else { Logger.d(TAG, "read empty List"); } cursor.close(); return result; } private void setFieldValue(Object t, Field field, String value) throws Exception { if (field.getType().equals(String.class) || field.getType().equals(Enum.class)) { field.set(t, value); } else if (field.getType().isPrimitive()) { field.set(t, FieldUtils.json2Value("\"" + value + "\"", field)); } else { field.set(t, FieldUtils.json2Value(value, field)); } } public <T> T selectById(Extra extra, Class<T> clazz) { TableInfo tableInfo = tableInfoUtils.get(clazz); Field idField = tableInfo.getId().getField(); String idColName = FieldUtils.getColumnNameByField(idField); String selection = null; String[] selectionArgs = null; if (extra != null) { Object[] o = getSelectionAndArgs(idColName, extra); if (o != null) { selection = o[0].toString(); selectionArgs = (String[]) o[1]; } } List<T> resultList = selectAll(clazz, selection, selectionArgs); if (resultList != null && resultList.size() > 0) return resultList.get(0); return null; } public <T> List<T> selectAll(Class<T> clazz, String selection, String[] selectionArgs, String orderBy, String limit) { return selectAll(clazz, selection, selectionArgs, null, null, orderBy, limit); } public <T> List<T> selectAll(Class<T> clazz, String selection, String[] selectionArgs) { return selectAll(clazz, selection, selectionArgs, null, null, null, null); } public <T> List<T> selectAll(Class<T> clazz) { return selectAll(clazz, null, null, null, null, null, null); } public void deleteAll(Extra extra, Class<?> clazz) { checkTableExist(clazz); TableInfo tableInfo = tableInfoUtils.get(clazz); Field idField = tableInfo.getId().getField(); String idColName = FieldUtils.getColumnNameByField(idField); String whereClause = null; String[] whereArgs = null; Object[] o = getSelectionAndArgs(idColName, extra); if (o != null) { whereClause = o[0].toString(); whereArgs = (String[]) o[1]; } int flag = getWd().delete(ClassUtils.getTableName(clazz), whereClause, whereArgs); Logger.d(TAG, String.format("delete %d rows", flag)); } public void delete(Extra extra, Object entity) { try { checkTableExist(entity.getClass()); SQLiteDatabase db = getWd(); Field idField = tableInfoUtils.get(entity.getClass()).getId().getField(); idField.setAccessible(true); idField.get(entity); String selection = null; String[] selectionArgs = null; if (extra == null) extra = new Extra(); extra.setId(idField.get(entity).toString()); Object[] o = getSelectionAndArgs(FieldUtils.getColumnNameByField(idField), extra); if (o != null) { selection = o[0].toString(); selectionArgs = (String[]) o[1]; } int flag = db.delete(ClassUtils.getTableName(entity.getClass()), selection, selectionArgs); if (flag > 0) Logger.w(TAG, String.format("删除, flag = %d , id = %s", flag, extra.getId())); else Logger.w(TAG, String.format("删除失败 , id = %s ", extra.getId())); } catch (Exception e) { e.printStackTrace(); } } public void delete(Extra extra, Class<?> clazz, Object id) { try { Object i = clazz.newInstance(); Field idField = tableInfoUtils.get(clazz).getId().getField(); idField.setAccessible(true); idField.set(i, id); delete(extra, i); } catch (Exception e) { e.printStackTrace(); } } public void delete(Class<?> clazz, String whereClause, String[] whereArgs) { checkTableExist(clazz); SQLiteDatabase db = getWd(); db.delete(tableInfoUtils.get(clazz).getTableName(), whereClause, whereArgs); } public void update(Extra extra, Object entity) { insert(extra, entity); } public int update(Class<?> clazz, ContentValues values, String whereClause, String[] whereArgs) { checkTableExist(clazz); SQLiteDatabase db = getWd(); return db.update(ClassUtils.getTableName(clazz), values, whereClause, whereArgs); } private void checkTableExist(Class<?> clazz) { if (!tableIsExist(tableInfoUtils.get(clazz))) { String sql = SqlBuilder.getCreatTableSQL(tableInfoUtils, clazz); Logger.d(TAG, String.format("create table, name = %s, sql = %s", ClassUtils.getTableName(clazz), sql)); db.execSQL(sql); } } private boolean tableIsExist(TableInfo table) { if (table.isCheckDatabese()) return true; Cursor cursor = null; try { String sql = "SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='" + table.getTableName() + "' "; Logger.d(TAG, sql); cursor = db.rawQuery(sql, null); if (cursor != null && cursor.moveToNext()) { int count = cursor.getInt(0); if (count > 0) { table.setCheckDatabese(true); // 检查表字段是否发生更改 cursor.close(); cursor = db.rawQuery("PRAGMA table_info" + "(" + table.getTableName() + ")", null); // table的所有字段名称 List<String> nameList = new ArrayList<String>(); if (cursor != null && cursor.moveToNext()) { do { nameList.add(cursor.getString(cursor.getColumnIndex("name"))); } while (cursor.moveToNext()); } cursor.close(); // 检查新对象的是否更新 List<Property> properties = ClassUtils.getPropertyList(table.getClazz()); Field idField = ClassUtils.getPrimaryKeyField(table.getClazz()); List<String> properList = new ArrayList<String>(); for (Property property : properties) { properList.add(property.getField().getName()); } // 1、新增对新字段自动添加的功能,暂时不能删除字段 2014-06-27 //--------------------------------------------------------------------------------------------------- List<String> newFieldList = new ArrayList<String>(); for (String field : properList) { boolean isNew = true; for (String tableField : nameList) { if (tableField.equals(field)) { isNew = false; break; } } if (isNew) newFieldList.add(field); } for (String newField : newFieldList) { db.execSQL(String.format("ALTER TABLE %s ADD %s TEXT", table.getTableName(), newField)); } // sqlite 暂时不支持drop column if (false) { List<String> deleteFieldList = new ArrayList<String>(); for (String tableField : nameList) { if (!"_id".equals(tableField) && !FieldUtils.CREATEAT.equals(tableField) && !FieldUtils.KEY.equals(tableField) && !FieldUtils.OWNER.equals(tableField) && !idField.getName().equals(tableField)) { boolean deleted = true; for (String field : properList) { if (field.equals(tableField)) { deleted = false; break; } } if (deleted) deleteFieldList.add(tableField); } } for (String deletedField : deleteFieldList) { db.execSQL(String.format("ALTER TABLE %s DROP %s", table.getTableName(), deletedField)); } } //--------------------------------------------------------------------------------------------------- // if (!nameList.contains(FieldUtils.getColumnNameByField(idField))) { // Logger.w(String.format("数据表%s更新了,删除该表", table.getTableName())); // db.execSQL("DROP TABLE " + table.getTableName()); // table.setCheckDatabese(false); // return false; // } // nameList.remove(FieldUtils.getColumnNameByField(idField)); // properList.remove(FieldUtils.getColumnNameByField(idField)); // // for (String property : properList) { // boolean notExist = true; // for (int i = 0; i < nameList.size(); i++) { // if (nameList.get(i).equals(property)) { // notExist = false; // break; // } // } // if (notExist) { // Logger.w(String.format("数据表%s更新了,删除该表", table.getTableName())); // db.execSQL("DROP TABLE " + table.getTableName()); // table.setCheckDatabese(false); // return false; // } // } return true; } } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); cursor = null; } return false; } public SQLiteDatabase getRd() { return db; } public SQLiteDatabase getWd() { return db; } static void dropDb(SQLiteDatabase db) { Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name != 'sqlite_sequence'", null); if (cursor != null) { while (cursor.moveToNext()) { db.execSQL("DROP TABLE " + cursor.getString(0)); } } if (cursor != null) { cursor.close(); cursor = null; } } static class SqliteDbHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 1; SqliteDbHelper(String dbName) { super(GlobalContext.getInstance(), dbName, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { dropDb(db); onCreate(db); } } static SQLiteDatabase openSdcardDb() { return openSdcardDb(SettingUtility.getStringSetting("db_name")); } static SQLiteDatabase openSdcardDb(String dbName) { File dbf = new File(getDBPath(dbName)); if (!dbf.exists()) { dbf.getParentFile().mkdirs(); try { if (dbf.createNewFile()) { Logger.d(TAG, String.format("create db on disk, path = %s", dbf.getAbsolutePath())); Logger.i(TAG, String.format("open db on disk, path = %s", dbf.getAbsolutePath())); return SQLiteDatabase.openOrCreateDatabase(dbf, null); } } catch (IOException ioex) { ioex.printStackTrace(); throw new RuntimeException("create db on disk failed", ioex); } } else { Logger.i(TAG, "open db on app dire"); return SQLiteDatabase.openOrCreateDatabase(dbf, null); } return null; } /** * Sdcard的DB path * * @param dbName * @return */ public static String getDBPath(String dbName) { Setting setting = SettingUtility.getSetting("path"); String sdcardPath = SystemUtility.getSdcardPath() + File.separator + SettingUtility.getStringSetting("root_path") + File.separator + "." + setting.getValue(); return sdcardPath + File.separator + dbName + ".db"; } public static class SqliteBatchBean<T> { public Extra extra; public List<T> list; } }