Android收藏集Android 技术开发Android知识

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

2018-04-05  本文已影响129人  289346a467da

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

本篇来讲解,如何实现多用户分库,在一些项目中,存在多用户登录的情况,比如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,这样我们就完成了,多用户分库。多用户分库的好处,在用户登录的时候,我们就不去再去同一个表中查询这个用户是什么用户了,直接操作用户,存到用户的私有数据库中,用户退出再登录后可直接从用户的私有数据库中恢复用户的数据。在大型的项目中一定会用到这个功能。

上一篇下一篇

猜你喜欢

热点阅读