• 移动架构-面向对象式数据库框架设计


    在以前,操作数据库的时候,往往是通过DBHelper类去操作数据库,然而这种操作方式存在其固有缺陷,因为其是创建在DB目录下,会随着软件的卸载而卸载,那么有时有需要在本次卸载并不删除数据库,又或者是通过面向对象的思想去操作数据库,主要是对比ormlite框架

    使用DBHelper

    在之前,使用DBHelper会比较繁琐,例如添加一个用户,会涉及以下操作

    public void saveUser(User name) {
    	DBHelper dbHelper = new DBHelper(this);
    	SQLiteDatabase db = dbHelper.getWritableDatabase();
    	db.execSQL("create table if not exists tb_user(name varchar(20),password varchar(10), )");
    	ContentValues values = new ContentValues();
    	values.put("name", user.getName());
    	values.put("password", user.getPassword());
    	db.beginTransaction();
    	int scheduleID = -1;
    	try {
    		db.insert("schedule", null, values);
    		db.setTransactionSuccessful();
    	} finally {
    	}
    	db.endTransaction();
    	db.close();
    }
    
    public void updateUser(User user, String name) {
    	DBHelper dbHelper = new DBHelper(this);
    	SQLiteDatabase db = dbHelper.getWritableDatabase();
    	db.execSQL("create table if not exists tb_user(name varchar(20),password varchar(10), )");
    	ContentValues values = new ContentValues();
    	values.put("name", user.getName());
    	values.put("password", user.getPassword());
    	db.beginTransaction();
    	try {
    		db.update("course", values, "name=?", new String[]{String.valueOf(user.getName())});
    		db.setTransactionSuccessful();
    	} finally {
    	}
    	db.endTransaction();
    	db.close();		
    }
    

    数据库框架的实现效果

    通过数据库框架的实现,我们可以更简单的操作数据库,以下就是实现其框架以后增加用户的使用例子,明显更加方便易行

    public void insert() {
    	User user = new User();
    	user.setName("jack");
    	user.setPassword("123456");
    	baseDao.insert(user);
    }
    

    数据库框架的设计思路

    将调用层与SQLiteDatabase进行隔离,在中间层完成相应的数据库框架设计
    其简单来说就是调用层不关心数据的存入过程,只需要满足调用层将对象给与中间层,中间层完成存储的相应操作
    通过映射关系使用HashMap得到数据库的key和value键值对
    通过注解维护表明与数据库存值的关系

    数据库框架实现

    设计一个数据库操作接口

    public interface IBaseDao<T> {
    
        //插入数据
        long insert(T entity);
    
        //更新数据
        int update(T entity, T where);
    
        //删除数据
        int detele(T where);
    
        //查询数据
        List<T> query(T where);
        List<T> query(T where, String orderBy, Integer startIndex, Integer limit);
    }
    

    添加注解类

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DbTable {
        String value();
    }
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DbField {
        String value();
    }
    

    实现接口声明的方法,通过反射和注解得到对象的值,然后进行相应操作

    public abstract class BaseDao<T> implements IBaseDao<T> {
    
        private static final String TAG = "BaseDao";
        private SQLiteDatabase database;//持有数据库操作类的引用
        private boolean isInit = false;//保证只实例化一次
        private Class<T> entityClass;//持有数据库表所对应的java类型
        private String tableName;
        private HashMap<String, Field> cacheMap;//维护表名与成员变量的映射关系
    
        //实例化
        protected boolean init(Class<T> entity, SQLiteDatabase sqLiteDatabase) {
            if (!isInit) {
                database = sqLiteDatabase;
                entityClass = entity;
                cacheMap = new HashMap<>();
                //拿到注解中的表名
                if (entity.getAnnotation(DbTable.class) != null) {
                    tableName = entity.getAnnotation(DbTable.class).value();
                } else {
                    tableName = entity.getClass().getSimpleName();
                }
                if (!database.isOpen()) {
                    return false;
                }
                if (!TextUtils.isEmpty(createTable())) {
                    database.execSQL(createTable());
                }
                initCacheMap();
                isInit = true;
            }
            return isInit;
        }
    
        //创建表,在子类中完成
        protected abstract String createTable();
    
        //维护映射关系
        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();//表的列名数组
                Field[] columnFields = entityClass.getFields();//拿到Filed数组
                for (Field field : columnFields) {
                    field.setAccessible(true);
                }
                //查找对应关系
                for (String columnName : columnNames) {
                    Field columnField = null;
                    for (Field field : columnFields) {
                        String fieldName = null;
                        if (field.getAnnotation(DbField.class) != null) {
                            fieldName = field.getAnnotation(DbField.class).value();
                        } else {
                            fieldName = field.getName();
                        }
                        if (columnName.equals(fieldName)) {
                            columnField = field;
                            break;
                        }
                    }
                    //找到对应关系,存入关系表
                    if (columnField != null) {
                        cacheMap.put(columnName, columnField);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                cursor.close();
            }
    
        }
    
        @Override
        public long insert(T entity) {
            Map<String, String> map = getValues(entity);
            ContentValues values = getContentValues(map);
            long result = database.insert(tableName, null, values);
            Log.d(TAG, "insert: result = " + result);
            return result;
        }
    
        @Override
        public int update(T entity, T where) {
            int result = -1;
            Map values = getValues(entity);
            ContentValues contentValues = getContentValues(values);
            Map whereClause = getValues(where);
            Condition condition = new Condition(whereClause);
            result = database.update(tableName, contentValues, condition.getWhereClause(), condition.getWhereArgs());
            return result;
        }
    
        @Override
        public int detele(T where) {
            int result = -1;
            Map values = getValues(where);
            Condition condition = new Condition(values);
            result = database.delete(tableName, condition.getWhereClause(), condition.getWhereArgs());
            return result;
        }
    
        @Override
        public List<T> query(T where) {
            return query(where, null, null, null);
        }
    
        @Override
        public List<T> query(T where, String orderBy, Integer startIndex, Integer limit) {
            Map values = getValues(where);
            String limitString = null;
            if (startIndex != null && limit != null) {
                limitString = startIndex + " , " + limit;
            }
            Condition condition = new Condition(values);
            Cursor cursor = database.query(tableName, null, condition.getWhereClause(),
                    condition.getWhereArgs(), null, null, orderBy, limitString);
            List<T> result = getResult(cursor, where);
            return result;
        }
    
        //通过Map构建ContentValues
        private ContentValues getContentValues(Map<String, String> map) {
            ContentValues contentValues = new ContentValues();
            Set keys = map.keySet();
            Iterator<String> iterator = keys.iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String value = map.get(key);
                if (value != null) {
                    contentValues.put(key, value);
                }
            }
            return contentValues;
        }
    
        //获取value值,存入Map
        private Map<String, String> getValues(T entity) {
            HashMap<String, String> result = new HashMap<>();
            Iterator<Field> filedsIterator = cacheMap.values().iterator();
            //循环遍历映射map的Filed
            while (filedsIterator.hasNext()) {
                Field colmunToField = filedsIterator.next();
                String cacheKey = null;
                String cacheValue = null;
                if (colmunToField.getAnnotation(DbField.class) != null) {
                    cacheKey = colmunToField.getAnnotation(DbField.class).value();
                } else {
                    cacheKey = colmunToField.getName();
                }
                try {
                    if (colmunToField.get(entity) == null) {
                        continue;
                    }
                    cacheValue = colmunToField.get(entity).toString();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                result.put(cacheKey, cacheValue);
            }
            return result;
        }
    
        //构建查询条件
        class Condition {
            //查询条件
            private String whereClause;
            private String[] whereArgs;
    
            public Condition(Map<String, String> whereClause) {
                ArrayList arrayList = new ArrayList();
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(" 1=1 ");
                Set keys = whereClause.keySet();
                Iterator<String> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    String value = whereClause.get(key);
                    if (value != null) {
                        //拼接条件查询语句 1=1 and name=? and password=?
                        stringBuilder.append(" and " + key + " =?");
                        arrayList.add(value);
                    }
                }
                this.whereClause = stringBuilder.toString();
                this.whereArgs = (String[]) arrayList.toArray(new String[arrayList.size()]);
            }
    
            public String getWhereClause() {
                return whereClause;
            }
    
            public String[] getWhereArgs() {
                return whereArgs;
            }
        }
    
        //获取查询结果
        private List<T> 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 = (Map.Entry) iterator.next();
                        String columnName = (String) entry.getKey(); //得到列名
                        Integer columnIndex = cursor.getColumnIndex(columnName); //拿到位置
                        Field 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) {
                                field.set(item, cursor.getInt(columnIndex));
                            } else if (type == Double.class) {
                                field.set(item, cursor.getDouble(columnIndex));
                            } else if (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 (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            return list;
        }
    }
    

    添加工厂模式

    public class BaseDaoFactory {
        private String sqliteDatabasePath;
        private SQLiteDatabase sqLiteDatabase;
        private static BaseDaoFactory instance = new BaseDaoFactory();
    
        public static BaseDaoFactory getInstance(){
            return instance;
        }
    
        public BaseDaoFactory() {
            sqliteDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "user.db";
            openDatabase();
        }
    
        public synchronized <T extends BaseDao<M>, M> T getDataHelper(Class<T> clazz, Class<M> entityClass) {
            BaseDao baseDao = null;
            //反射得到对象类型
            try {
                baseDao = clazz.newInstance();
                baseDao.init(entityClass, sqLiteDatabase);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return (T) baseDao;
        }
    
        private void openDatabase() {
            //打开数据库,如果不存在则创建
            this.sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath,null);
        }
    }
    

    编写测试类

    @DbTable("tb_user")
    public class User {
    
        @DbField("name")
        public String name;
    
        @DbField("password")
        public String password;
    
        public User() {
        }
    
        public User(String name, String password) {
            this.name = name;
            this.password = password;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "name: " + name + ",password: " + password;
        }
    }
    

    测试类的数据操作,继承BaseDao,完成数据库的创建

    public class UserDao extends BaseDao{
        @Override
        protected String createTable() {
            return "create table if not exists tb_user(name varchar(20),password varchar(10))";
        }
    }
    

    在主活动中测试

    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "cj5785";
        IBaseDao<User> baseDao;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            baseDao = BaseDaoFactory.getInstance().getDataHelper(UserDao.class, User.class);
        }
    
        public void onSave(View view) {
            User user = new User("jack", "123456");
            baseDao.insert(user);
        }
    
        public void onUpdate(View view) {
            User where = new User();
            where.setName("jack");
            User user = new User("json", "654321");
            baseDao.update(user, where);
        }
    
        public void onDelete(View view) {
            User user = new User();
            user.setName("json");
            baseDao.detele(user);
        }
    
        public void onQuery(View view) {
            User user = new User();
            user.setName("jack");
            List<User> list = baseDao.query(user);
            Log.d(TAG, "查询到数据条目:" + list.size());
            for (User u : list) {
                Log.d(TAG, u.toString());
            }
        }
    }
    

    测试结果
    添加五条"jack"数据
    添加数据
    更新"jack"数据为"json"
    更新数据
    再添加五条"jack"数据
    再添加数据
    查询"jack"数据
    数据查询
    删除"json"数据
    删除数据

    对比OrimLite框架

    OrimLite框架插入1000条数据,在我测试机上,测试十次,平均用时:5110ms
    自定义框架插入1000条数据十次平均用时:6430ms

  • 相关阅读:
    Unique constraint on single String column with GreenDao2
    Unique constraint on single String column with GreenDao
    将String转换成InputStream
    TypeError: unsupported operand type(s) for +: 'float' and 'str'
    Could not find private key file: AuthKey_NCD8233CS5.p8
    【Winows10】添加桌面小工具(在桌面显示时钟,日历)
    【Windows10】禁用开机启动项
    SQL如何查询出某一列中不同值出现的次数?
    使用 管理项目依赖
    Warning: Python 3.6 was not found on your system…
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664613.html
Copyright © 2020-2023  润新知