Hibernate 动态条件查询

Hibernate 条件动态查询

Hibernate 是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装。提供了高效的程序与数据库之间的交互接口。从产品特性上看,Hibernate 是一个全自动的 orm 框架,这意味着无须用户再手动编写 SQL 语句,只需要通过 Hibernate 就可以自动生成 SQL 语句。这从使用的角度上来看是非常方便的。除此之外,Hibernate 还做到了对数据库层的抽象,使得程序能够做到在切换数据库(如从 Oracle 切换到 MySQL )时完全无感,不需要大规模的改动即可完成数据库的切换。Hibernate 通过自定义查询语言 Hql 抹平了不同数据库语言之间的差异性,让开发者可以专注于业务代码而避免了浪费时间在不同数据库的 sql 语言上。

与之相对的是 Mybatis ,作为国内最流行的 orm 框架,Mybatis 具有简单易用的特点。相对于 Hibernate ,Mybatis 会看起来更小巧一些。作为一款半自动化的框架,Mybatis 将功能交给了用户 ,使得 Mybatis 具有什么能力是看用户有什么样的能力。国内比较著名的 Mybatis 插件有 分页插件PageHelper,自动生成sqlTkMapper,和Beetl等(我知道的就这些)。通过与这些插件搭配,使得Mybatis 在国内大多数场景下完胜 Hibernate。

这两款框架在选型上各有千秋,言归正站。我想在这里描述的是一个动态SQL的场景,根据参数内容的不同自动拼接不同的 sql。

多条件动态查询

场景

当前我有一个场景,对应用户对User 映射 用户表 user:

public class User{
    // 主键id
    Integer id;
    // 用户姓名
    String name;
    // 用户年龄
    Integer age;
}

对应表如下:

CREATE TABLE user(
	id INT(11) NOT NULL AUTO_INCREMENT,
    name varchar(255) NOT NULL DEFAULT "",
    age int(11) NOT NULL DEFAULT 0,
    PRIMARY KEY(id)
)ENGINE="InnoDb" CHARSET="utf8mb4";

INSERT INTO user(name,age) values
("张三",25)
,("李四",23)
,("王五",20)
;

我现在有一个查询场景:

当我们用 User 对象去查询数据库,我希望当我的 name 属性为空时不使用该属性查询,同理 age 也一样。

Mybatis 动态 SQL 查询

当我们使用 Mybatis 对上述需求进行实现时,我们只需在 Mapper 中编写 xml 即可:

<select id="selectByUser" resultType="com.example.User">
	SELECT id,name,age
    FROM user
    <where>
    	<if test="name != null and name != ''">
        	AND name = #{name}
        </if>
        <if test="age != null and age <= 0">
        	AND age = #{age}
        </if>
    </where>
    LIMIT 10
</select>

从上面的 xml中可以看到,在拼接 SQL 前会对属性值进行判断,如果满足条件则根据对应查询,如果不满足条件则跳过该条件。

这便是 Mybatis 的动态 SQL 功能,Mybatis 框架会在拼接执行的 SQL 前会根据我们编写的 xml 进行条件判断,并根据判断结果生成 SQL 语句 。通过这种方式我们可以轻松的实现 动态查询的功能。

Hibernate 根据条件动态 SQL 查询

Mybatis 通过 xml 使得我们避免的编写一堆 SQL 然后根据条件判断的麻烦。那么 Hibernate 作为一款全自动框架,它的 SQL 是自动生成的,也就是如果我们直接使用的话是没有办法像 Mybatis 一样根据条件动态生成想要执行的 SQL 的。那么问题来了 Hibernate 有这样的功能吗?

答案是肯定的,虽然实现起来要复杂一点。

Hibernate 的动态条件查询需要通过实现 Specification 接口来实现如下:

/**
 * 用户接口
 */
public interface UserDAO extends JpaRepository<User,Long>, JpaSpecificationExecutor<User>{
}

@Autowired
UserDAO userDAO;
/**
 *
 * 查询方法,传入参数 User ,根据 user 的属性动态构造查询条件
 */
public List<User> queryByUser(User user) {
    // 指定条件
    final Specification<User> specification = new Specification<User>() {
        /**
             *
             * @param root root 参数为传入的 user 参数
             * @param query 查询条件的拼接
             * @param cb 构造条件
             * @return 构造结果
             */
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            final ArrayList<Predicate> preds = new ArrayList<>();
            // 当 name 不为空时,构造 name = #{name} 条件
            if (StringUtils.hasText(user.getName())) {
                preds.add(cb.equal(root.get("name"), user.getName()));
            }
            // 当 age 不为空时,构造 age  = #{age} 条件
            if (Objects.nonNull(user.getAge()) && user.getAge() > 0) {
                preds.add(cb.equal(root.get("age"), user.getAge()));
            }
            // 将条件通过 and 联结在一起
            return cb.and(preds.toArray(new Predicate[0]));
        }
    };
    return userDAO.findAll(specification);
}

参考资料

Spring Data JPA 基本使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值