JPA基础学习三-----JPQL语句学习

        jpql是JPA操作数据库的语言,它的底层还是sql语句,就是我们的jpql语言最终还是会转化为sql语句到数据库去做相应的操作。所以JPAQL与sql语句很相识,它们的关键字是一样的,最大的一个区别就是JPQL是面向对象的,我们可以在语句中使用一些面向对象的语法(new 对象,调属性)。建议初学者,可以先学习sql语言。

1.JPQL语句的使用规范

JPA的查询语言,类似于sql

 1.里面不能出现表名,列名,只能出现java的类名,属性名,区分大小写

 2.出现的sql关键字是一样的意思,不区分大小写

 3.不能写select * 要写select 别名

2.JPQL基本查询语句(我这里没有使用框架,以后想Spring等框架使用起来会更加方便)

    1.查询所有

   Select 别名 from 类 别名

   Query query = entityManager.createQuery(jpql); 关联sql语句

   List<Employee> resultList = query.getResultList(); 返回查询结果

/**
 * 查询所有员工【查询实体类型】
 *       resultList.forEach(e-> System.out.println(e));foreach
                foreach的另一种写法
 */
@Test
public void testQueryAll(){
    String jpql="select o from Employee o";
    EntityManager entityManager = JPAUtils.getEntityManager();//JPAUtils是我抽取的一个获取
                                                                EntityManager对象的工具类
    Query query = entityManager.createQuery(jpql);
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e));
    entityManager.close();
}

2.查询一个字段(某一行/列)
 查询所有员工的姓名和所属部门名称【查询特定属性】
             jpql:是面向对象的的语言,可以使用Java语言
              返回为一个Object的数组
              Arrays.asList(e)  转化,将e转化为字符
 


@Test
public void testQuery1(){
    String jpql="select o.name,o.department.name from Employee o";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Object[]> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(Arrays.asList(e)));
    entityManager.close();
}

   

/**
 * 2.2.2.查询所有员工的姓名和所属部门名称【查询特定属性】
 *       直接new
 */
@Test
public void testQuery2(){
    String jpql="select new Employee(o.name,o.department.name) from Employee o";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e));
    entityManager.close();
}

    3.条件查询  where

/**
 * 查询出所有在成都和广州工作的员工【查询结果过滤】
 *    ? 占位符  从1开始
       给占位符复值
          query.setParameter(1, "成都");  
          query.setParameter(2, "广州");
          List<Employee> resultList = query.getResultList();

 */
@Test
public void testQuery3(){
    String jpql="select o from Employee o where o.department.city=?1 or o.department.city=?2";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    //给?设置值
    query.setParameter(1, "成都");
    query.setParameter(2, "广州");
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e.getName()+"  "+ e.getDepartment().getCity()));
    entityManager.close();
}

条件集合查询  in(条件1,条件2....)

/**
 * 查询出在恩宁路和八宝街上班的员工信息【使用IN】
 *        in(条件1,条件2...)
 */
@Test
public void testQuery7(){
    String jpql="select o from Employee o where o.department.street in(?1,?2)";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    query.setParameter(1,"恩宁路" ).setParameter(2, "八宝街" );
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e));
    entityManager.close();
}

4.范围查询

按照范围查找(BigDecimal 类型:赋值是new 它的对象)
/**
 * 查询出工资在5000-6000的员工【使用BETWEEN..AND..】
 *
 *         salary 是BigDecimal 类型,所以我们不能直接拿值,需要new BigDecimal(值),这个就是值
 */
@Test
public void testQuery8(){

    String jpql="select o from Employee o where o.salary between ?1 and ?2";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    query.setParameter(1,new BigDecimal(5000)).setParameter(2,new BigDecimal(6000) );
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e.getName()+" "+e.getSalary()));
    entityManager.close();

5.模糊查询

/**
 *
 * 查询出姓名包含er或者en的员工【使用LIKE】
 *
 *      like:where o.name like ?1 or o.name like ?2
 *        不能在语句中直接写“%?%”
 *
 */
@Test
public void testQuery9(){
    String jpql="select o from Employee o  where o.name like ?1 or o.name like ?2";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    query.setParameter(1,"%er%").setParameter(2,"%en%");
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e.getName()));
    entityManager.close();
}

6.查询去重

 /**
 * 查询出有员工的部门【distinct】
 *     使用distinct:只查询不为空的
 */
@Test
public void testQuery10(){
    String jpql="select  distinct o.department from Employee o ";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Department> resultList = query.getResultList();
    resultList.forEach(e-> System.out.println(e));
    entityManager.close();
}

3.集合的操作

集合的操作(size)  集合都有size
          集合在JPA中经常出现,对集合的操作(size)
          sql里面没有size(最终换成sql的count查询)
注意:使用size就是操作集合,那么我们就必需配置员工与部分双向的关系,让部门也可以找到对应的员

/**
 * 集合的操作(size)  集合都有size
 *         集合在JPA中经常出现,对集合的操作(size)
 *         sql里面没有size(最终换成sql的count查询)
 *               注意:使用size就是操作集合,那么我们就必需配置员工与部分双向的关系,让部门也可以找到对应的员工
 */
/**
 * 2.4.1.查询出有员工的部门【size】//必须配置双向一对多:部门和员工
 *
 */
@Test
public void testJPA11(){
    String jpql="select o from Department o where o.employees.size>0";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Department> resultList = query.getResultList();
    resultList.forEach(e -> System.out.println(e.getName()));
    entityManager.close();
}

 

4.JOIN/left JOIN

JPA中的JOIN和LEFT JOIN(使用SQL/JPQL对比)
       sql:
            select * 表1 join 表2 on 条件
       jpql:
            1.不写on语句
            2.模型 模型的别名 join 写前面模型别名.出来的对象属性
              PQL中是支持关连(JOIN/LEFT JOIN)
               两个法则:1.自己消除笛卡尔积  2.关连 对象的别名.属性

/**
 * JPA中的JOIN和LEFT JOIN(使用SQL/JPQL对比)
 *       sql:
 *           select * 表1 join 表2 on 条件
       jpql:
            1.不写on子句
            2.模型 模型的别名 join 写前面模型别名.出来的对象属性
              PQL中是支持关连(JOIN/LEFT JOIN)
               两个法则:1.自己消除笛卡尔积  2.关连 对象的别名.属性
 */
/**
 * 查询出所有员工及部门名称【JOIN/LEFT JOIN】
 *
 */
@Test
public void testJPA14(){
    //language=JPAQL
    String jpql="select o.name,d.name from Employee o left join o.department d";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Object[]> resultList = query.getResultList();
    resultList.forEach(e -> System.out.println(Arrays.asList(e)));
    entityManager.close();
}
/**
 *2.5.2.查询出市场部员工信息及电话
 */
@Test
public void testJPA15(){
    //language=JPAQL
    String jpql = "select e,p from Phone p join p.employee e join e.department d where d.name='市场部'";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Object[]> resultList = query.getResultList();
    resultList.forEach(e -> System.out.println(Arrays.asList(e)));
    entityManager.close();
}

5.聚合函数 

/**
 * 查询出各个项目参与人数报表
 */
  @Test
  public void testJPA17(){
      String jpql="select p.name,count(e) from Project p left join p.employees e group by p.name";
      EntityManager entityManager = JPAUtils.getEntityManager();
      Query query = entityManager.createQuery(jpql);
      List<Object[]> resultList = query.getResultList();
      resultList.forEach(e-> System.out.println(Arrays.asList(e)));
      entityManager.close();

  }

6.子查询

/**
 * 子查询:查询出大于平均工资的员工信息
 *         一个查询的结果作为另一个查询的条件与参数
 */
@Test
public void testJPA18(){
    String jpql="select o from Employee o where o.salary > (select avg(e.salary) from  Employee e )";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    List<Employee> resultList = query.getResultList();
    resultList.forEach(e -> System.out.println(e));
    entityManager.close();
}

7.分页

  1.真分页:在数据库一次查询只查当前页的值   每次查询时间一样

  2.假分页:在数据库一次全部查出来,然后放到缓冲中,每次查询只到缓存中拿,第一次特别慢

Jpql的分页:

       setFirstResult:从第几条开始
       setMaxResults:第几页查询多少条数据

      Long singleResult = (Long)query.getSingleResult();//返回非Long

//假分页
@Test
 public void testPage(){
    String jpql="select o from Employee o";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    //开始设置分页
    /**
     * setFirstResult:从第几条开始
     * setMaxResults:第几页查询多少条数据
     *   limit 0,5
     *   从第几条开始 : (currentPage-1)*pageSize
     */
    query.setFirstResult(5).setMaxResults(5);
    List<Employee> resultList = query.getResultList();
    resultList.forEach(employee -> System.out.println(employee) );
    entityManager.close();
}
//获取总数据
@Test
public void testConut(){
    String jpql="select count(o) from Employee o";
    EntityManager entityManager = JPAUtils.getEntityManager();
    Query query = entityManager.createQuery(jpql);
    Long singleResult = (Long)query.getSingleResult();//返回非Long
    System.out.println(singleResult);
    entityManager.close();
}

8.原生SQL

我们可以在语句中直接写sql

如何使用sql:

entityManager.createNativeQuery(sql);//运行原生SQL

createNativeQuery(sql);//运行原生sql,拿到的是集合

createNativeQuery(sql, Employee.class);  拿到的是集合

    @Test
    public void testSQL(){
        String sql="select * from Employee ";
        EntityManager entityManager = JPAUtils.getEntityManager();
        Query nativeQuery = entityManager.createNativeQuery(sql);
        List<Object[]> resultList = nativeQuery.getResultList();
        resultList.forEach(employee -> System.out.println(Arrays.asList(employee)));
        entityManager.close();
    }
    //返回一个对象
    @Test
    public void testSQL2(){
        String sql="select * from Employee ";
        EntityManager entityManager = JPAUtils.getEntityManager();
        Query nativeQuery = entityManager.createNativeQuery(sql, Employee.class);
        List<Employee> resultList = nativeQuery.getResultList();
        resultList.forEach(employee -> System.out.println(employee));
        entityManager.close();
    }

9.事务:同生共死

1.原子性(atomic):

      最小单位

      对于其数据修改,要么全都执行,要么全都不执行

2.一致性(consistent):

     事务在完成时,必须使所有的数据都保持一致状态。

3.持久性(Duration):

    事务完成之后,它对于系统的影响是永久性的。

4.隔离性(insulation):

      当并发的事务访问或修改数据库中相同的数据(同一行同一列)时,通常需要采取必要的隔离机制。

事务并发所作的修改必须与任何其它并发事务所作的修改隔离使用锁来实现隔离机制

10.事务并发

通常为了获得更好的运行性能,各种数据库都允许多个事务同时运行,这就是事务并发。

事务并发的问题

  1. 第一类丢失更新:
  2. 第二类丢失更新
  3. 脏读
  4. 不可重复读
  5. 泛读

脏读,泛读,与不可重复读:考虑比较小,影响也比较小,在开发中如果要求不高可以不考虑

解决第一,二类丢失更新(使用锁)

  悲观锁:

      是将我们需要的数据全部加锁,他不释放事务,别人是不能访问。性能极差,不推荐使用

     如果使用了悲观锁(加了一个行锁),如果事务没有被释放,就会造成其他事务处于等待

    使用entityManager.find(class,id,LockModeType);加悲观锁,相当于发送SELECT ... FOR UPDATE(加了一个行锁)

使用entityManager.lock(object,LockModeType);加悲观锁,相当于发送SELECT id FROM ... FOR UPDATE(加了一个行锁)

     乐观锁:

     大家都可以来,但是只有满足条件的才能获取,提交成功。比较常用

    使用version:添加一个私有字段Integer version,不由程序员维护,由JPA自己维护

11.JPQL的代码优化

  1. 使用双向一对多关联,不使用单向一对多
    1. 灵活使用单向多对一关联
    2. 不用一对一,用多对一取代(不要使用共享主键一对一,使用唯一外键一对一)
    3. 配置对象二级缓存,不使用集合二级缓存,如果使用了集合二级缓存,集合里面的对象也必须二级缓存;查询缓存(jpql查询),没有查询条件才使用查询缓存
    4. 组合关系集合使用list(顺序,重复),多对多集合使用set(性能更好)
    5. 表字段要少,表关联不要怕多,有二级缓存撑腰,设计表尽量达到第三范式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值