文章目录
Day39 JPQL
jpql概念
JPQL语句是面向对象的查询语言
- JPQL和SQL很像,查询关键字都是一样的
- 唯一的区别是:JPQL是面向对象的
JPQL书写规则
JPA的查询语言,类似于sql
-
里面不能出现表名,列名,只能出现java的类名,属性名,区分大小写
-
出现的sql关键字是一样的意思,不区分大小写
-
不能写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";
- 集合元素: Obejct[]
-
查询出所有在成都和广州工作的员工【查询结果过滤】
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中多表查询注意事项:
- 如果要连接多表,并不是连接多个domain,而是连接的属性
- 不需要使用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=?";
-
查询出各个部门员工的平均工资和最高工资【使用聚集函数】
- 聚合函数
- sum
- count
- avg
- min
- 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 幻想读、不可重复读和脏读都不允许