Java反射应用:基于Redis实现一个通用的Dao类

本文介绍如何利用Java反射和Redis实现一个通用的Dao类,适用于多种实体类的存储和查询,包括增删改查操作。通过创建反向索引来优化查询效率,使用lettuce作为Redis数据库驱动。
摘要由CSDN通过智能技术生成

前言

   ​ Redis是开源的,内存数据结构存储的健值数据库。即Key: Value形式来存储每一个数据,以Redis String、Hash、List类型为例:

  • String 相当于 Map<String, String>
  • Hash 相当于 Map<String, Map<String, String>>
  • List 相当于 Map<String, List<String>>

每一个记录都相当于一个Map键值对,并根据不同的值类型,使用不同类型的Map。

如何用Redis存储一个对象实体

那么如何使用这种结构来存储一个对象记录呢,例如User {id: "user1", name: "sundial dreams", age: 21, sex: "man"},其实存储方式有很多,我们挑一种简单的存储方式,即直接用Hash类型来存储,以user:id当成一个键,如下:

user:user1=> {name: "sundial dreams", age: 21, sex: "man"}

但是我们存储了一堆的User,然后我们需要获取所有的User咋办呢,最暴力的方式是遍历所用的键,然匹配出user:为前缀的键,但是效率上肯定不高,因此我们可以使用一个List来存储当前的用户Id,并以user:list为键,如下

user:list => ["user1"]

那如果我们需要根据用户名来查询一条用户的信息呢,最暴力的方式还是枚举出所有的用户,然后再匹配姓名,考虑到效率问题,我们使用反向索引的方式来实现,即以user:username为键值为userid的List类型,比如

user:sundial dreams => ["user1"]

如果还想根据年龄来查找用户,也可以为年龄构建一个反向索引,即

user:21 => ["user1"]

有了这个思路,其他的都是同样的道理。

基于Java反射的Dao类

可以看到,User实体的存储其实也是有固定模式的(其实其他实体也可以用类似的存储模式),因此可以写一个UserDao类来存储每一个User实体,基本方法包括增删改查,但是,如果我们的实体类一换,即不是User,而是其他类,如Article,那么我们不得不写一个ArticleDao类,并重新实现跟UserDao类似的方法,这不符合代码复用原则,即同一份代码,在UserDao的实现类里要写一遍,而在ArticleDao的实现类里也得写一遍,所以我使用Java的反射和泛型来实现了一个公共的Dao类,并且以Dao<User> userDao = new Dao()的方式来产生操作User实体类的Dao对象,同理Dao<Article> articleDao = new Dao()来产生操作Article实体类的Dao对象,这样同一个方法只需实现一次即可,提高代码复用率。

IDao接口的定义

基于上面的思路我们定义如下接口:

/**
 * Dao 接口
 *
 * @param <E>
 */
interface IDao<E> {
    //查询所有 返回一个Map类型的值,其中键为Id,值为泛型类对象(实体类对象,如User类的对象)
    Map<String, E> queryAll() throws Exception;

    //基于域查询 返回值与queryAll一致, 根据对应属性的值来查询,以User类为例,queryByField("name", "sundial dreams") => 查询叫做sundial dreams的用户ID
    Map<String, E> queryByField(String field, String value) throws Exception;

    //基于Id查询
    Tuple2<String, E> queryById(String id) throws Exception;

    //插入操作
    String insert(E ele) throws Exception;

    //更新操作
    String update(String id, E ele) throws Exception;

    //删除操作
    void delete(String id) throws Exception;
}

定义实体,以User实体为例

/**
 * User实体类
 * 因为我实现的Dao是通用的Dao,而且在构建反向索引时不可能为类每一个属性都构建,
 * 比如可以通过name查询对应用户,但没有根据密码来查询用户的说法。
 * 因此,我只会为设置为public的属性构建反向索引,并且定义的实体类名,最后会对应上Redis数据库上存储的名字
 */
class User {
    public String name; // 用户名  会构建反向索引
    public String birthday; // 生日 会构建反向索引
    public String area; // 所在地区 会构建反向索引
    private String sex; // 性别 不会构建反向索引
    private String password; // 密码 不会构建反向索引

    public User() {
    }

    public User(String name, String birthday, String password, String area, String sex) {
        this.name = nam
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sundial dreams

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值