1.JPQL的使用
简单查询
- 查询所有员工【查询实体类型】
String jpql = "select o from Employee o";
Query query = entityManager.createQuery(jpql);
List<Employee> list = query.getResultList();
- 查询所有员工的姓名和所属部门名称【查询特定属性】
//代码(只有一个参数的话可以使用List<String>接收数据)
//代码(多个参数可以使用List<Object[]>接收数据)
String jpql = "select o.name,o.department.name from Employee o";
Query query = entityManager.createQuery(jpql);
List<Object[]> list = query.getResultList();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
3.查询出所有在成都和广州工作的员工【查询结果过滤】
String jpql = "select o from Employee o where o.department.city=? or o.department.city=?";
Query query = entityManager.createQuery(jpql);
query.setParameter(1, "成都").setParameter(2, "广州");
List<Employee> list = query.getResultList();
- 查询出所有员工信息,按照月薪排序【查询排序】
String jpql = "select o from Employee o order by o.salary desc";
Query query = entityManager.createQuery(jpql);
List<Employee> list = query.getResultList();
for (Employee employee : list) {
- 使用关联对象属性排序
String jpql = "select o from Employee o order by o.department.id desc";
Query query = entityManager.createQuery(jpql);
List<Employee> list = query.getResultList();
- 【distinct】去重
String jpql = "select distinct o.department from Employee o";
Query query = entityManager.createQuery(jpql);
List<Department> list = query.getResultList();
7.jpql 中所有的集合都有size属性
查询员工人数大于0 的部门
EntityManager entityManager = JPAUtils.getEntityManager();
String jpql = "select o from Department o where o.employees.size>0";
Query query = entityManager.createQuery(jpql);
List<Department> list = query.getResultList();
- Join的使用
1.不写on子句
2.模型 模型的别名 join 写前面模型别名.出来的对象属性
String jpql = "select o,d.name from Employee o left join o.department d";
Query query = entityManager.createQuery(jpql);
List<Object[]> list = query.getResultList();
9.Jpql中的聚集函数
1.avg() 平均值
2.sum() 求和
3.count() 累计
4.min() 最小值
5.max() 最大值
String jpql = "select avg(o.salary),max(o.salary) from Employee o group by o.department.name";
Query query = entityManager.createQuery(jpql);
10子查询 【将一个查询的结果作为另一个查询的条件】
String jpql = "select e from Employee e where e.salary> (select avg(o.salary) from Employee o )";
Query query = entityManager.createQuery(jpql);
List<Employee> list = query.getResultList();
11.分页查询的设置
String jpql = "select o from Employee o";
Query query = entityManager.createQuery(jpql);
// 从那里开始取数据,索引从0开始
int firstResult = (currentPage - 1) * pageSize;
// 取多少条
int maxResults = pageSize;
query.setFirstResult(firstResult).setMaxResults(maxResults);
2.JPA对原生sql 的使用
1.返回一个数组
String sql = "select * from Employee";
Query nativeQuery = entityManager.createNativeQuery(sql);
List<Object[]> list = nativeQuery.getResultList();
- 将查询结果封装成一个对象
String sql = "select * from employee";
Query query = entityManager.createNativeQuery(sql, Employee.class);
List<Employee> list = query.getResultList();
- 添加查询条件
String sql = "select * from employee where salary > ? ";
Query query = entityManager.createNativeQuery(sql, Employee.class);
query.setParameter(1,new BigDecimal("5000"));
List<Employee> list = query.getResultList();
3.事务并发
1.事务并发的定义
事务:一组要么同时成功,要么同时失败的操作。
事务的4个特性ACID
原子性(atomic),事务是最最小的不能分隔的单元;对于其数据修改,要么全都执行,要么全都不执行
一致性(consistent),事务在完成或失败,所有的数据都保持一致状态。
隔离性(insulation),事务与事务之间互相不能改变。
持久性(Duration),事务完成之后,它对于系统的影响是永久性的。
事务并发【多个事务同时发生】引发的问题
-
脏读
1.张三的原工资为4000, 财务人员将张三的工资改为了8000(但未提交事务)
2.张三读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!(在缓存中读取)
3.而财务发现操作有误,回滚了事务,张三的工资又变为了4000 像这样,张三记取的工资数8000是一个脏数据。
解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。 -
幻读【虚读】
1.张三的原工资为4000, 财务人员将张三的工资改为了8000(但未提交事务)
2.张三读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!(在缓存中读取)
3.而财务发现操作有误,回滚了事务,张三的工资又变为了4000 像这样,张三记取的工资数8000是一个脏数据。
解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。 -
不可重复读
在一个事务中前后两次读取的结果并不致,导致了不可重复读。
1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成
2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。 -
第一类丢失更新
库存是1件
当事务A和事务B同时修改某行的值,
1.事务A将数值改为0并提交,购买了一件
2.事务B将数值改为0并提交,也购买了一件。这时数据的值为0,事务A所做的更新将会丢失。(相当于就卖出去2件商品)
解决办法:对行加锁,只允许并发一个更新事务。(JPA中的悲观锁,乐观锁) -
第二类丢失更新
多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变
2.解决事务并发的问题 悲观锁 乐观锁
乐观锁
1.Version方式(整数,存储空间小)
// 添加一个私有字段Integer version,不由程序员维护,由JPA自己维护
@Version
private Integer version;
StaleObjectStateException异常 说明乐观锁起作用了
悲观锁
4.优化JPA的方式
- 使用双向一对多关联,不使用单向一对多
- 灵活使用单向多对一关联
- 不用一对一,用多对一取代(不要使用共享主键一对一,使用唯一外键一对一)
- 配置对象二级缓存,不使用集合二级缓存,如果使用了集合二级缓存,集合里面的对象也必须二级缓存;查询缓存(jpql查询),没有查询条件才使用查询缓存
- 组合关系集合使用list(顺序,重复),多对多集合使用set
- 表字段要少,表关联不要怕多,有二级缓存撑腰,设计表尽量达到第三范式
JPA难在什么地方 -> 细节(练,思考)太多了,性能太难控制了(经验)