美文网首页Android收藏集Android 技术开发Android知识
理解数据库框架设计 part3 - 多用户分库实现

理解数据库框架设计 part3 - 多用户分库实现

作者: 289346a467da | 来源:发表于2018-04-05 16:32 被阅读129次

    在上几篇目中,讲解了如何自动建表
    以及增删改查
    代码.

    本篇来讲解,如何实现多用户分库,在一些项目中,存在多用户登录的情况,比如QQ ,切换qq的登录账号,一些用户的操作需要存到数据库中,如果我们存到同一张表中,查询修改都非常麻烦。在比如一些类似滴滴打车之类的,APP 有用户端 和 司机端,现在大部分APP 都是用户端 和 司机端 在一个APP 上操作,如果我们都存在tb_car 的一个数据库表中,那么就需要判断是否是司机等一些操作,如果再加上权限的一些操作对数据库表的操作会相当的麻烦。


    image.png

    如何实现分库呢?

    看下图:


    image.png

    如上图所示,我们可以将用户登录的信息存到tb_user的表中,然后根据当前登录的用户state = 1 来生成用户私有数据库的路径和私有的数据库连接池,然后创建用户的私有数据库,这样用户的所有操作,就可以存到用户的私有数据库中,当切换另一个用户时,操作的是另一个用户的私有数据库,当切换回之前的用户时,可以根据之前用户的私有数据库,恢复之前用户的数据。

    代码实现分库

    在BaseDao 基础上我们新建一个UserDao,用来实现改变用户的登录状态和获取当前登录的用户。用于维护公有数据,新登录的状态state = 1;之前登录过的用户状态state = 0

     public class UserDao extends BaseDao<User> {
    
        private static final String TAG = "UserDao";
    
        @Override
        public long insert(User entity) {
            // 查到表中的所有的用户记录
            List<User> userList = query(new User());
            User where;
            for (User user : userList) {
                // 将所有的用户的登陆状态 改为 0
                where = new User();
                where.id = user.id;
                user.state = "0";
                Log.e(TAG, "用户: " + user.name + " 未登录");
                update(user, where);
            }
            Log.e(TAG, "用户: " + entity.name + " 登录");
            // 将当前用户的状态给为 1 然后插入
            entity.state = "1";
            return super.insert(entity);
        }
    
        /**
         * 得到当前登录的user
         */
    
        public User getCurrentUser() {
            User user = new User();
            user.state = "1";
            List<User> query = query(user);
            if (query != null && query.size() > 0) {
                return query.get(0);
            }
            return null;
        }
    }
    

    根据当前登录的用户,生成当前用户的私有数据库的路径(可以是在某个文件夹下: 用户id/login.db)

    public enum PrivateDataBaseEnums {
        database("");
        private String value;
    
        PrivateDataBaseEnums(String value) {
        }
    
        // 用于生产路径
        public String getValue() {
            UserDao baseDao = BaseDaoFactory.getInstance().getBaseDao(UserDao.class, User.class);
            User currentUser = baseDao.getCurrentUser();
            if (currentUser != null) {
                File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
                if (!file.exists()) {
                    file.mkdirs();
                }
                return file.getAbsolutePath() + "/n" + currentUser.id + "_login.db";
            }
            return null;
        }
    }
    

    之后我们为当前登录的用户建立私有数据库的连接池,在之前的BaseDaoFactory的基础上,我们新建一个 用户私有数据库的BaseDaoSubFactory 工厂继承BaseDaoFactory,当用户在进行数据库操作时,用来生产BaseDao对象

     /**
         * 生产basedao 对象
         *
         * @param entityClass
         * @param <T>         User 对象
         * @param <M>         BaseDao {@link BaseDao}
         * @return
         */
        public synchronized <M extends BaseDao<T>, T> M getSubBaseDao(Class<M> daoClass, Class<T> entityClass) {
            BaseDao baseDao = null;
            if (map.get(PrivateDataBaseEnums.database.getValue()) != null) {// 判断当前用户私有的数据库是否存在
                return (M) map.get(PrivateDataBaseEnums.database.getValue());
            }
            // 如果不存在则创建当前用户的私有数据库
            Log.e("jett", "生成数据库文件的位置:" + PrivateDataBaseEnums.database.getValue());
            subSQLiteDatabase = SQLiteDatabase.openOrCreateDatabase(PrivateDataBaseEnums.database.getValue(), null);
            try {
                baseDao = daoClass.newInstance();
                baseDao.init(subSQLiteDatabase, entityClass);
                map.put(PrivateDataBaseEnums.database.getValue(), baseDao);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return (M) baseDao;
        }
    

    这样我们就可以用getSubBaseDao 来进行数据库的操作,数据都会存到用户的私有数据库中去。

    对代码进行测试

     BaseDao userDao = BaseDaoFactory.getInstance().getBaseDao(UserDao.class, User.class);
    
       /** 模仿用户切换登录的操作  */
       public void clickSubLogin(View view) {
            // 登录以后  服务器返回用户信息
            prim.com.lib_db.sub_qlite.User user = new prim.com.lib_db.sub_qlite.User();
            user.id = i;
            user.name = "张三" + (++i);
            user.pass = "123";
            // 在公共信息中插入到公共数据库中
            userDao.insert(user);
        }
       
       /** 模仿用户登录后操作,将数据存到私有数据库中 */
       public void clickSubInster(View view) {
            // 插入私有数据库
            Photo photo = new Photo();
            photo.path = "data/data/img.jpg";
            photo.time = "2018-4-5";
    
            // 插入到当前登录的用户的私有数据库中
            PhotoDao subBaseDao = BaseDaoSubFactory.getInstance().getSubBaseDao(PhotoDao.class, Photo.class);
            subBaseDao.insert(photo);
        }
    

    这里注意 PhotoDao extends BaseDao

    运行项目:


    image.png

    点击两次登录,可以看到 张三1 state = 0 成了未登录的状态,而张三2 state = 1 变成已登录的状态。


    image.png

    我们在看下tb_user表中的数据是:


    image.png

    我们点击分库插入按钮,然后去存放私有数据库的路径下,有没有创建用户的私有数据库,我这里直接将数据库存到sd卡中了。下图说明,为我们创建了用户的私有数据库了。


    image.png

    然后我们,去看私有数据库中的 tb_photo 表中是否有数据

    image.png

    可以看到确实有数据存在。

    然后我们在点击登录按钮和分库插入按钮。


    image.png
    image.png

    OK,可以看到,新登录的用户私有数据库创建成功了。

    多点击两次分库插入按钮,然后我们去n2_login.db 看下tb_photo 表中的数据。


    image.png

    然后我们再看一下上一个登录用户的n1_login.db tb_photo 表中的数据.


    image.png

    ok,这样我们就完成了,多用户分库。多用户分库的好处,在用户登录的时候,我们就不去再去同一个表中查询这个用户是什么用户了,直接操作用户,存到用户的私有数据库中,用户退出再登录后可直接从用户的私有数据库中恢复用户的数据。在大型的项目中一定会用到这个功能。

    相关文章

      网友评论

        本文标题:理解数据库框架设计 part3 - 多用户分库实现

        本文链接:https://www.haomeiwen.com/subject/vbtdhftx.html