面向对象的SQL语句——JPQL

Day39 JPQL

jpql概念

JPQL语句是面向对象的查询语言

  1. JPQL和SQL很像,查询关键字都是一样的
  2. 唯一的区别是:JPQL是面向对象的

JPQL书写规则

JPA的查询语言,类似于sql

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

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

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

    SELECT o[o.property,o.property*] FROM Entity o
    [WHERE conditions]
    [GROUP BY conditions]
    [HAVING conditions]
    [ORDER BY o.property[ASC|DESC]]

案例

  • 查询所有员工【查询实体类型】

    String jpql = "from Employee";

    相当于

    String jpql = "select o from Employee o";String jpql = "select o from cn.itsource.jpa.domain.Employee o";

  • 查询所有员工的姓名和所属部门名称【查询特定属性】
    **注意: **在jpql语句中,查询数据的时候,如果查询的数据结果值不能和domain中的属性一一对应,那返回的集合元素应该是Object[]

    • 集合元素: Obejct[]

      String jpql = "select o.name,o.department.name from Employee o";
    • 集合元素:对象

      String jpql = "select new Employee(o.name,o.department.name) from Employee o";
  • 查询出所有在成都和广州工作的员工【查询结果过滤】
    String jpql = "select o from Employee o where o.department.city=? or o.department.city=?";

  • 查询出所有员工信息,按照月薪排序【查询排序】
    String jpql = "select o from Employee o order by o.salary desc ";

  • 查询出所有员工信息,按照部门编号排序【使用关联对象属性排序】
    String jpql = "select o from Employee o order by o.department.id desc ";

  • 查询出在恩宁路和八宝街上班的员工信息【使用IN】
    String jpql = "select o from Employee o where o.department.street in(?,?) ";

  • 查询出工资在5000-6000的员工【使用BETWEEN…AND…】
    String jpql = "select o from Employee o where o.salary between ? and ?";

  • 查询出姓名包含er或者en的员工【使用LIKE】
    String jpql = "select o from Employee o where o.name like ? or o.name like ?";

  • 查询出有员工的部门【distinct】

    • 仅仅返回部门名
      String jpql = "select distinct o.department.name from Employee o ";
    • 返回部门对象
      String jpql = "select distinct o.department from Employee o ";
  • 查询出有员工的部门【size】

    **注意:**如果你要使用size来查,必须对象中拥有集合 因为对象是没有size的
    String jpql = "select o from Department o where o.employees.size>0";

  • 查询出部门信息,按照部门的员工人数排序
    String jpql = "select o from Department o order by o.employees.size";

  • 查询出没有员工参与的项目【对集合使用size】
    String jpql = "select o from Project o where o.employees.size=0";

  • 查询出所有员工及部门名称【JOIN/LEFT JOIN】

    • 多表查询,在jpa中多表查询默认使用是内连接,没有外连接
    • 如果你要使用外连接,必须手动的编写sql语句
    • 在jpa中多表查询注意事项:
      1. 如果要连接多表,并不是连接多个domain,而是连接的属性
      2. 不需要使用on消除笛卡尔积,因为在jpa中它会自动消除笛卡尔积

    String jpql = "select o,d.name from Employee o join o.department d";

  • 查询出市场部员工信息及电话
    String jpql = "select e,p.number from Phone p join p.employee e join e.department d where d.name=?";

  • 查询出各个部门员工的平均工资和最高工资【使用聚集函数】

    • 聚合函数
      1. sum
      2. count
      3. avg
      4. min
      5. max

    String jpql = "select o.department.name,avg(o.salary),max(o.salary) from Employee o group by o.department.name";

  • 查询出各个项目参与人数报表
    String jpql = "select p.name,count(e) from Project p left join p.employees e group by p.name";

  • 查询出大于平均工资的员工信息
    String jpql = "select o from Employee o where o.salary>(select avg(salary) from Employee)";

  • 分页查询

  public void test20(){
  	    String jpql = "from Employee";
  	    EntityManager entityManager = JPAUtil.openEntityManager();
  	    Query query = entityManager.createQuery(jpql);
  	    //开始位置   开始条数 = (currentPage-1)*pageSize;
  	    query.setFirstResult(5);
  	    //每页展示多好条
  	    query.setMaxResults(5);
  	    //分页查询的列表
  	    List<Employee> resultList = query.getResultList();
  	    for (Employee employee : resultList) {
  	        System.out.println(employee);
  	    }
  	    String countJpql = "select count(o) from Employee o ";
  	    Query query1 = entityManager.createQuery(countJpql);
  	    //获取总条数
  	    Long count = (Long)query1.getSingleResult();
  	    System.out.println(count);
  	}

事务并发(乐观锁)

事务4个特性

  • 原子性(atomic),事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行(事务不能被分割,要么都成功要么都失败)
  • 一致性(consistent),事务在完成时,必须使所有的数据都保持一致状态。
  • 隔离性(insulation),由事务并发所作的修改必须与任何其它并发事务所作的修改隔离。
  • 持久性(Duration),事务完成之后,它对于系统的影响是永久性的。

事务并发

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

隔离机制

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

解决并发问题的途径是什么?答案是:采取有效的隔离机制。

怎样实现事务的隔离呢?隔离机制的实现必须使用锁

事务并发带来的问题

JPA只能处理第一、二类丢失更新,其他3种必须由数据库自己处理

第一类丢失更新:(在秒杀场景会出现问题)

库存是1件

当事务A和事务B同时修改某行的值,

1.事务A将数值改为0并提交,购买了一件

2.事务B将数值改为0并提交,也购买了一件。这时数据的值为0,事务A所做的更新将会丢失。(相当于就卖出去2件商品)

解决办法:对行加锁,只允许并发一个更新事务。(JPA中的悲观锁,乐观锁)

在这里插入图片描述

脏读

1.张三的原工资为4000, 财务人员将张三的工资改为了8000(但未提交事务)

2.张三读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!(在缓存中读取)

3.而财务发现操作有误,回滚了事务,张三的工资又变为了4000 像这样,张三记取的工资数8000是一个脏数据。

解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。

在这里插入图片描述

虚读(幻读)

目前工资为4000的员工有10人。

1.事务1,读取所有工资为4000的员工。

2.这时事务2向employee表插入了一条员工记录,工资也为4000

3.事务1再次读取所有工资为4000的员工共读取到了11条记录,

解决办法:如果在操作事务完成数据处理之前,任何其他事务都不可以添加新数据,则可避免该问题。
在这里插入图片描述

不可重复读

在一个事务中前后两次读取的结果并不致,导致了不可重复读。

1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成

2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.

3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000

解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
在这里插入图片描述

第二类丢失更新

多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变

在这里插入图片描述

数据库的隔离级别

MySql默认隔离级别为:Repeatable Read(可能会出现虚读)

Oracle 支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别

默认隔离级别为READ COMMITTED

READ UNCOMMITTED 幻想读、不可重复读和脏读都允许。

READ COMMITTED 允许幻想读,不可重复读,不允许脏读

REPEATABLE READ 允许幻想读,不允许不可重复读和脏读

SERIALIZABLE 幻想读、不可重复读和脏读都不允许

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值