关于数据库等封装之前有写过一篇博客Android数据库面向对象之增、删、改、查这篇博客写的是将数据库存储在sd卡中,android6.0以后关于sd卡的操作就需要动态申请权限,如果在工具类中使用时权限的申请就没有那么方便,即使在activity或者fragment中时候,使用的频次比较高时,老是申请权限也比较麻烦,存储在data目录下虽然存储的数据大小有限,但是不需要去做权限的申请,使用起来方便很多,这里是针对data目录下的存储的封装,基本上和sd卡的存储封装大同小异,有些细微的变化。
系统提供了SQLiteOpenHelper这个类用于数据的创建和数据库的版本管理,在使用是extends SQLiteOpenHelper该类,会要求去重写onCreate()方法和onUpgrade()方法,在数据创建时会回调onCreate()方法,数据库版本更新是会回调onUpgrade()方法;
public class MySqliteHelper extends SQLiteOpenHelper {
private BaseDao baseDao;
public MySqliteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public MySqliteHelper(Context context) {
super(context, ConstantValue.DATABASE_NAME, null, ConstantValue.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//执行建表语句
db.execSQL(baseDao.createTable());
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//数据库版本变动会回调这里
}
public synchronized , M> T
getDataHelper(Class clazz, Class entityClass) {
try {
//利用反射实例化BaseDao
baseDao = clazz.newInstance();
//初始化BaseDao中的参数
baseDao.init(entityClass);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return (T) baseDao;
}
}
MySqliteHelper弄好后,需要定义一个接口提供数据库增删改查操作的一系列方法;
public interface IBaseDao {
/**
* 插入数据库
* @param entity 插入的数据对象
* @return
*/
Long insert(T entity);
/**
* 批量插入数据库
* @param entity 插入的数据对象
* @return
*/
void insert(List entity);
/**
* 更新数据库
* @return
*/
int update(ContentValues contentValues, String whereClause, String[] whereArgs);
/**
* 删除数据库
* @return
*/
int delete(String selection,String[] selectionArgs);
/**
* 查询数据
* @param where 查询条件
* @return
*/
List query(T where);
/**
* 查询数据
* @param where 查询条件
* @param orderBy 查询排序
* @param startIndex 开始的位置
* @param limit 查询限制条件
* @return
*/
List query(T where, String selection, String[] selectionArgs, String orderBy, Integer startIndex, Integer limit);
/**
* 查询数据 用于多条件查询
* @param sql 查询语句
* @return
*/
List query(String sql);
}
数据增删改查接口定义好了,需要一个实现类去做具体的增删改查的逻辑;
public abstract class BaseDao implements IBaseDao {
private static volatile MySqliteHelper helper;
private boolean isInit = false;
private Class entityClass;
private SQLiteDatabase database;
private String tableName;
/**
* 维护这表名与成员变量名的映射关系
* key---》表名
* value --》Field
*/
private HashMap cacheMap;
public static MySqliteHelper getInstance(Context context) {
if (helper == null) {
synchronized (MySqliteHelper.class) {
if (helper == null) {
helper = new MySqliteHelper(context.getApplicationContext());
}
}
}
return helper;
}
protected synchronized boolean init(Class entity) {
if (!isInit) {
entityClass = entity;
//getReadableDatabase getWritableDatabase 创建或者打开数据库
//如果数据库不存在则会创建数据库,如果数据库存在直接打开数据库
//默认情况下都是打开或者创建可读可写的数据库,如果磁盘已盘就是可读数据库
database = helper.getWritableDatabase();
//判断数据库是否打开
if (!database.isOpen()) {
return false;
}
tableName = getTableName();
cacheMap = new HashMap<>();
//缓存维护映射关系
initCacheMap();
isInit = true;
}
return isInit;
}
/**
* 维护映射关系
*/
private void initCacheMap() {
String sql = "select * from " + this.tableName + " limit 1 , 0";
Cursor cursor = null;
try {
cursor = database.rawQuery(sql, null);
//表的列名数组
String[] columnNames = cursor.getColumnNames();
//拿到Filed数组
Field[] colmunFields = entityClass.getFields();
for (Field filed : colmunFields) {
//设置私有可以访问
filed.setAccessible(true);
}
//开始找对应关系
for (String columnName : columnNames) {
//如果找到对应的Field就赋值给他
Field columnFiled = null;
for (Field filed : colmunFields) {
String filedName = "";
if (filed.getAnnotation(DbFiled.class) != null) {
filedName = filed.getAnnotation(DbFiled.class).value();
} else {
filedName = filed.getName();
}
//如果表的列名等于了成员变量的注解名字
if (columnName.equals(filedName)) {
columnFiled = filed;
break;
}
}
//找到了对应关系
if (columnFiled != null) {
cacheMap.put(columnName, columnFiled);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭游标
cursor.close();
}
Log.e("cacheMap--->", cacheMap.size() + "");
}
@Override
public Long insert(T entity) {
Map map = getValues(entity);
ContentValues values = getContentValues(map);
Long insert = database.insert(tableName, null, values);
return insert;
}
@Override
public void insert(List entity) {
//批量插入采用事务
database.beginTransaction();
for (T data : entity) {
insert(data);
}
database.setTransactionSuccessful();
database.endTransaction();
}
@Override
public int update(ContentValues contentValues, String whereClause, String[] whereArgs) {
int result = -1;
result = database.update(tableName, contentValues, whereClause, whereArgs);
return result;
}
@Override
public int delete(String selection, String[] selectionArgs) {
int result = database.delete(tableName, selection, selectionArgs);
return result;
}
@Override
public List query(T where) {
return query(where, null, null, null, null, null);
}
@Override
public List query(T where, String selection, String[] selectionArgs, String orderBy, Integer startIndex, Integer limit) {
String limitString = "";
if (startIndex != null && limit != null) {
limitString = startIndex + " , " + limit;
}
Cursor cursor = database.query(tableName, null, selection, selectionArgs,
null, null, orderBy, limitString);
List result = getResult(cursor, where);
//关闭游标
cursor.close();
return result;
}
@Override
public List query(String sql) {
return null;
}
/**
* 根据查询条件获取查询结果
*
* @param cursor 数据库游标
* @param where 查询条件
* @return 根据查询条件返回的结果
*/
private List getResult(Cursor cursor, T where) {
List list = new ArrayList();
Object item;
while (cursor.moveToNext()) {
try {
item = where.getClass().newInstance();
//遍历缓存的映射关系
Iterator> iterator = cacheMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
//得到列名
String colomunName = entry.getKey();
//然后以列名拿到 列名在游标的位置
Integer columnIndex = cursor.getColumnIndex(colomunName);
Field field = entry.getValue();
Class> type = field.getType();
if (columnIndex != -1) {
//反射赋值
if (type == String.class) {
field.set(item, cursor.getString(columnIndex));
} else if (type == Integer.class || type == int.class) {
field.set(item, cursor.getInt(columnIndex));
} else if (type == Double.class || type == double.class) {
field.set(item, cursor.getDouble(columnIndex));
} else if (type == Long.class || type == long.class) {
field.set(item, cursor.getLong(columnIndex));
} else if (type == byte[].class) {
field.set(item, cursor.getBlob(columnIndex));
} else {
continue;
}
}
}
list.add(item);
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}
/**
* 将缓存的map数据转成ContentValues
*
* @param map
* @return
*/
private ContentValues getContentValues(Map map) {
ContentValues contentValues = new ContentValues();
Set keys = map.keySet();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = map.get(key);
if (value != null) {
contentValues.put(key, value);
}
}
return contentValues;
}
/**
* 根据数据对象和数据库表字段,将数据转成key value的形式
*
* @param entity 数据对象
* @return 转换后获取到的数据
*/
private Map getValues(T entity) {
Map result = new HashMap<>();
//遍历缓存数据,并进行映射
Iterator fieldIterator = cacheMap.values().iterator();
while (fieldIterator.hasNext()) {
Field colmunToFiled = fieldIterator.next();
String cacheKey = "";
String cacheValue = "";
if (colmunToFiled.getAnnotation(DbFiled.class) != null) {
cacheKey = colmunToFiled.getAnnotation(DbFiled.class).value();
} else {
cacheKey = colmunToFiled.getName();
}
try {
if (null == colmunToFiled.get(entity)) {
continue;
}
cacheValue = colmunToFiled.get(entity).toString();
} catch (Exception e) {
e.printStackTrace();
}
result.put(cacheKey, cacheValue);
}
return result;
}
/**
* 创建表语句
*
* @return
*/
public abstract String createTable();
/**
* 表名
*
* @return
*/
public abstract String getTableName();
}
在实现类中提供了createTable()和getTableName()两个抽象方法,具体的创建表语句和表名需要根据实际的由子类去实现;
public class PersonDao extends BaseDao {
@Override
public String createTable() {
String sql = "create table if not exists " + getTableName() + "(" + ConstantValue._ID + " Integer primary key," + ConstantValue.NAME + " varchar(10)," + ConstantValue.AGE + " Integer)";
return sql;
}
@Override
public String getTableName() {
return ConstantValue.TABLE_NAME;
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbFiled {
String value();
}
public class ConstantValue {
//数据库库版本
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "name.db";
//表名
public static final String TABLE_NAME = "person";
//数据库存储字段
public static final String _ID = "_id";
public static final String NAME = "name";
public static final String AGE = "age";
}
接下来调用下增删改查方法,看下实现的如何,在使用之前需要先初始化MySqliteHelper和创建BaseDao对象;
private PersonDao dataHelper = BaseDao.getInstance(this).getDataHelper(PersonDao.class, Person.class);
初始化完毕后就可以调用相应的方法,进行数据库操作了,先看下单条数据的插入;
/**
* 插入数据库
*
* @param view
*/
public void addDB(View view) {
Person person = new Person();
person._id = 100;
person.name = "张国焘";
person.age = 89;
dataHelper.insert(person);
}
/**
* 批量插入数据库
*
* @param view
*/
public void addMoreDB(View view) {
List list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Person person = new Person();
person._id = i;
person.name = "张国焘" + i;
person.age = i;
list.add(person);
}
dataHelper.insert(list);
}
/**
* 修改数据
*
* @param view
*/
public void updateDB(View view) {
ContentValues contentValues = new ContentValues();
contentValues.put(ConstantValue.NAME, "李四8");
String where = ConstantValue.NAME + "=?";
String[] whereArgs = new String[]{"张国焘7"};
dataHelper.update(contentValues, where, whereArgs);
}
/**
* 删除数据
*
* @param view
*/
public void deleteDB(View view) {
String where = ConstantValue.NAME + "=?";
String[] selectionArgs = new String[]{"张国焘5"};
dataHelper.delete(where, selectionArgs);
}
/**
* 查询数据库
*
* @param view
*/
public void queryDB(View view) {
Person user = new Person();
user.name = "张国焘1";
List query = dataHelper.query(user);
Log.e("TAG", "数据库查询数据" + query.size());
for (Person user1 : query) {
Log.e("TAG", "姓名:" + user1.name + "年龄:" + user1.age);
}
}
/**
* 分页查询
* @param view
*/
public void queryByLimit(View view){
Person user = new Person();
user.name = "张国焘1";
List query = dataHelper.query(user,null,null,null,0,8);
Log.e("TAG", "数据库查询数据" + query.size());
for (Person user1 : query) {
Log.e("TAG", "姓名:" + user1.name + "年龄:" + user1.age);
}
}
源码地址