优秀的编程知识分享平台

网站首页 > 技术文章 正文

sql动态传参在springData中的应用(补充)

nanyue 2024-10-01 13:05:16 技术文章 4 ℃


在之前的文章提到过关于sql动态传参在springData中的应用,下面补充一下关于原生sql和springData的同一需求下的两种不同的写法:

需求:contoller层传递一个map给service层,需要从map中取到三个参数(pid、enVisible、type)给数据库进行查询返回结果集。

需求明细:

1.不确定前端是否会传递这三个参数,换言之,这三个参数不一定能够取到;

2.如果传递传递参数pid、enVisible,如果能取到值的话,则按照相应的条件进行筛选;

3.type参数传递,如果传递参数为空则,则筛选出符合其他条件的全部数据;如果传递为0,则筛选出type为1和2的数据;如果传递参数不为0(为1或2或3),则筛选出与之对应的数据。

处理逻辑放在service层实现方法1——springData通过Specification进行实现:

dao层写法:

public interface PermissionDao extends JpaRepository<Permission, String>, JpaSpecificationExecutor<Permission> {

}

service写法:

 public List<Permission> findAll(Map<String,Object> map){
 		 //1.需要查询条件
 Specification<Permission> specification = new Specification<Permission>() {
 @Override
 public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
 //查询条件list接受
 List<Predicate> list = new ArrayList<Predicate>();
 //pid:父id应用
 if (!StringUtils.isEmpty(map.get("pid"))){
 list.add(criteriaBuilder.equal(root.get("pid").as(String.class),(String)map.get("pid")));
 }
 //enVisible:0:查询平台所有权限(最高权限);1:查询组织的权限
 if(!StringUtils.isEmpty(map.get("enVisible"))){
 list.add(criteriaBuilder.equal(root.get("enVisible").as(String.class),(String)map.get("enVisible")));
 }
 // type:查询全部权限列表type:0: 菜单+按钮(权限点) 1:菜单 2;按钮(权限点) 3:api接口
 if (StringUtils.isEmpty(map.get("type"))){
 String type = (String)map.get("type");
 CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("type"));
 if("0".equals(type)){
 in.value(1).value(2);
 }else {
 in.value(Integer.parseInt(type));
 }
 }
 return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
 }
 };
 return permissionDao.findAll(specification);
 }

处理逻辑放在dao层实现方法2——springData通过原生sql进行实现:

dao层写法:

public interface PermissionDao extends JpaRepository<Permission, String>, JpaSpecificationExecutor<Permission> {
 @Query(value = "select * from pe_permission where (pid = ?1 or ?1 is null) and (en_visible = ?2 or ?2 is null) and IF(?3 is null,(1 = 1),IF(?3 = 0,type in (1,2), type = ?3))",nativeQuery = true)
 List<Permission> selectList(Object pid, Object enVisible, Object type);
}

service写法:

 public List<Permission> findAll(Map<String,Object> map){
 		 return permissionDao.selectList(map.get("pid"),map.get("enVisible"),map.get("type"));
 }

两种方式经测试都可以实现需求,但从代码量上来说,第二种实现方式肯定是优于第一种方式的;但从程序的可读性来说,如果sql比较好的同学,那么第二种方式可能跟适合一些,但是如果是springData学的比较好的同学可能更喜欢第一种吧。

第一种方式基本就是借用springData封装好的接口去实现逻辑的,再此我不赘述了,关于第二种方式,我多啰嗦几句:(pid = ?1 or ?1 is null)和(en_visible = ?2 or ?2 is null)在上一篇文章也说过,基本的意思就是判断传递过来的参数是否为空,如果不为空就按照传递过来的参数进行检索,如果为空的话就相当与没条件一个意思。

至于IF函数是mysql数据库种自带的函数,IF(表达式1,表达式2,表达式3):表达式1返回布尔值,如果返回为true,那么去执行表达式2;如果返回为false,那么执行表达式3。但个人不推荐这种写法,原因是必须是mysql数据或者该数据库中必须含有这个函数;所以换个数据库的话,就必须要换个函数,其他数据库不是很了解,如果是Oracle数据库的话,得将这个函数换成Nvl2()这个函数,用法是一样的,也可以实现同样的效果,不过这样也暴露出这种方式的一个问题,如果写原生sql中含有某种数据库特定的数据库函数,那么它的移植性就会差一点。

关于springData中动态传参的见解就这些了,希望大家喜欢,不说了,我去写bug了哈。

最近发表
标签列表