JPA调用存储过程

1.例子

   @Transactional
    public BasAccount findByAccount(String account) {
        System.out.println(account);
        Query q = em.createNativeQuery("{call QueryBasAccount(?)}",BasAccount.class);
        q.setParameter(1, account);
        List<BasAccount> list = q.getResultList();
        BasAccount ba = null;
        if(list.size()>0){
             ba = (BasAccount)q.getResultList().get(0);
        }
        return ba;
    }

 

2.语法

   {call methodName(?)} Query .setParameter(1, param1);

   {call methodName(?,?)} Query .setParameter(1, param1);Query .setParameter(2, param2);

 

3.createNativeQuery

   概述:

         在JPA 2.0 中我们可以使用entityManager.createNativeQuery()来执行原生的SQL语句。

         但当我们查询结果没有对应实体类时,query.getResultList()返回的是一个List<Object[]>。

         也就是说每行的数据被作为一个对象数组返回。

   常见的用法是这样的:

          Query query = entityManager.createNativeQuery("select id, name, age from t_user"); 
          List rows = query.getResultList(); 
          for (Object row : rows) { 
             Object[] cells = (Object[]) row; 
             System.out.println("id = " + cells[0]); 
             System.out.println("name = " + cells[1]); 
             System.out.println("age = " + cells[2]); 
          }

    总结:这样用会使代码非常不容易让人理解, 究竟下标为0的元素到底是什么, 不去数查询语句是不知道的,

             而且一旦查询语句被调整,Java代码也要一起调整。这时候我们想如果返回的是Map的话,用起来会清晰的多。

 
             可惜的是JPA的API中并没有提供这样的设置。其实很多JPA的底层实现都是支持返回Map对象的。例如:
             EclipseLink的query.setHint(QueryHints.RESULT_TYPE, ResultType.Map); 
             Hibernate的.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
      
     个人理解:返回不需要知道实体对象
     另一种:
         Query query = entityManager.createNativeQuery("select id, name, age from t_user"); 
         query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); 
         List rows = query.getResultList(); 
         for (Object obj : rows) { 
                Map row = (Map) obj; 
                System.out.println("id = " + row.get("ID")); 
                System.out.println("name = " + row.get("NAME")); 
                System.out.println("age = " + row.get("AGE")); 
          }
        注:这里需要注意的是, 用Map肯定要比用Object数组来的效率低。所以你要看性能下降是否在可接受范围内。
                再就是在我的Hibernate 4.2.x的环境下,无论你原生SQL中写的是大写字母还是小写字母,返回的字段名都是大写的。
                当然你可以通过自定义ResultTransformer的形式对字段名进行一定的处理, 甚至是返回自己需要的POJO。
 

4.createQuery与createSQLQuery(createNativeQuery)区别

   第一点:前者用的hql语句进行查询,后者可以用sql语句查询  --也可以用实体
   第二点:前者以hibernate生成的Bean为对象装入list返回,后者则是以对象数组进行存储

                 所以使用createSQLQuery有时候也想以hibernate生成的Bean为对象装入list返回

       例子:

              @Override
              public List<Commodity> findCommodityByActyId(int activityId) {
                  String sql = "SELECT aa.ACTIVITYSCOPE_VALUE from activity_scope aa LEFT JOIN activity_rule ar ON aa.ACTIVITYRULE_ID = ar.ACTIVITYRULE_ID LEFT JOIN"
                 +" activity ac on ar.ACTIVITY_ID = ac.ACTIVITY_ID where ac.ACTIVITY_ID ="+activityId+" and ac.status=3";
                 System.out.println(sql);
                 Query query = entityManager.createNativeQuery(sql);
                 List<Integer> commoditiyIds = (List<Integer>)(query.getResultList());
                 List<Commodity> commodities = new ArrayList<Commodity>();
                 for(int i=0;i<commoditiyIds.size();i++) {
                    String sql2 = "from Commodity c where c.commodityId=:c1";
                    Query query2 = entityManager.createQuery(sql2);
                    query2.setParameter("c1", commoditiyIds.get(i));
                    Commodity c = (Commodity) query2.getResultList().get(0);
                    commodities.add(c);
                  }
                  return commodities;
              }

   第三点:这两种都是动态查询,也不被缓存

 

5.自定义函数

    //调用数据库自定义函数
    @Query(value="SELECT a FROM Client a WHERE function('DISTANCE',?1,?2,a.LONGITUDE,a.LATITUDE)<=2")
     public List<Client> findNearClient(Float LONGITUDE,Float LATITUDE);

 

6.jpa通过解析方法名创建查询和使用@Query创建自定义查询

   第一种: jpa通过解析方法名创建查询:

                 JpaRepository会对Repository层所有未加@Query的方法名进行校验,不符合规范会报错,除非添加@Query注解;

                  查询方法以find | read | get 开头 ——建议统一用find开头;

                  格式findBy**And/Or**;findBy**NotLike等,具体参考如图:

               

      

           例子:

                List<User>   findByUserName(String  username);

                User  findByUserNameAndPassword(String  username,String password);

 

            注意:按方法名解析的查询方法通常只适用于单表查询,且建议where条件参数不多于三条的情况下,返回值通常上对应表的实体Bean,

                      通常用实体类List类型;具体要看返回结果,当返回值与类型不匹配时会造成查询错误;

 

   第二种:使用@Query创建自定义查询

           概述:@Query注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL查询语句即可;

           查询策略:

                      <jpa:repositories>提供了guery-lookup-strategy 属性,用以指定查找的顺序。它有如下三 个取值:

                      第一:create-if-not-found: 如果方法通过@Query指定了查询语句,

                              则使用该语句实现查询, 如果没有,则查找是否定义了符合条件的命名查询,

                              如果找到,则使用该命名查询,如果两者都没有找到,

                              则通过解析方法名字来创建查询。这是query-lookup-strategy 属性的默认值;

                     第二:create:通过解析方法名字来创建查询。即使有符合的命名查询,

                                或者方法通过@Query 指定的查询语句,都将会被忽略;

                     第三:use-declared-query: 如果方法通过@Query指定了查询语句,则使用该语句实现查询,

                                如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;

                                如果两者都没有找到,则抛出异常。

 

     使用:

         import com.xdja.timingDemo.model.Cert;

        import org.springframework.data.jpa.repository.JpaRepository;
        import org.springframework.data.jpa.repository.Modifying;
        import org.springframework.data.jpa.repository.Query;
        import org.springframework.data.repository.query.Param;
        import org.springframework.stereotype.Repository;
        import java.util.Date;
        import java.util.List;
       import java.util.Optional;
       @Repository
       public interface CertDao extends JpaRepository<Cert,Integer> {
    
          //方法名解析JpaRepository<Cert,Integer>  @Repository这两个是重点
          Optional<Cert>  findById(Integer Id);
 
         List<Cert> findAll();
         //自定义解析
         @Query(value = "select  expire_date_time from Cert where time < '1609344000'")
         List<Date> findAllDate();
 
         @Modifying //DML操作需添加该注解
         @Query(value = "delete  from Cert where time < '1609344000'")
         void deleteTime();
 
         @Modifying
         @Query(value = "update  Cert set status = 0 where time < '1550645979'")
         void updateStatus();
    
         @Modifying
         @Query(value = "update  Cert set status = 0 where time < :time ")
         void updateStatusByTime(@Param("time") Long time);
      }
  

 

学习来源:https://www.cnblogs.com/LittleDirewolf/p/5121626.html

                  https://blog.csdn.net/qq_31678877/article/details/52935942

                  http://www.voidcn.com/article/p-vhqlnady-po.html

                  //@query自定义函数

                  https://blog.csdn.net/qq_33296651/article/details/89027914

                 //解析方法名的查询

                 https://blog.csdn.net/weixin_42209368/article/details/87918285

posted @ 2020-09-10 11:26  小窝蜗  阅读(2883)  评论(0编辑  收藏  举报