JPQL_事物并发_锁机制

本文详细介绍了JPQL的基本使用方法,包括简单查询、属性查询、结果过滤、排序及分页等。同时,深入探讨了JPA对原生SQL的支持、事务并发问题及其解决方案,如脏读、幻读、不可重复读等问题的规避方法,以及悲观锁和乐观锁的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.JPQL的使用
简单查询

  1. 查询所有员工【查询实体类型】
String jpql = "select o from Employee o";
  Query query = entityManager.createQuery(jpql);
  List<Employee> list = query.getResultList();
  1. 查询所有员工的姓名和所属部门名称【查询特定属性】
//代码(只有一个参数的话可以使用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();
  1. 查询出所有员工信息,按照月薪排序【查询排序】
  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) {
  1. 使用关联对象属性排序
    String jpql = "select o from Employee o order by o.department.id desc";
      Query query = entityManager.createQuery(jpql);
      List<Employee> list = query.getResultList();
  1. 【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();
  1. 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();

  1. 将查询结果封装成一个对象
String sql = "select * from employee";
Query query = entityManager.createNativeQuery(sql, Employee.class);
List<Employee> list = query.getResultList();

  1. 添加查询条件
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. 脏读
    1.张三的原工资为4000, 财务人员将张三的工资改为了8000(但未提交事务)
    2.张三读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!(在缓存中读取)
    3.而财务发现操作有误,回滚了事务,张三的工资又变为了4000 像这样,张三记取的工资数8000是一个脏数据。
    解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。

  2. 幻读【虚读】
    1.张三的原工资为4000, 财务人员将张三的工资改为了8000(但未提交事务)
    2.张三读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!(在缓存中读取)
    3.而财务发现操作有误,回滚了事务,张三的工资又变为了4000 像这样,张三记取的工资数8000是一个脏数据。
    解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。

  3. 不可重复读
    在一个事务中前后两次读取的结果并不致,导致了不可重复读。
    1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成
    2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
    3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000
    解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。

  4. 第一类丢失更新
    库存是1件
    当事务A和事务B同时修改某行的值,
    1.事务A将数值改为0并提交,购买了一件
    2.事务B将数值改为0并提交,也购买了一件。这时数据的值为0,事务A所做的更新将会丢失。(相当于就卖出去2件商品)
    解决办法:对行加锁,只允许并发一个更新事务。(JPA中的悲观锁,乐观锁)

  5. 第二类丢失更新
    多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变
    2.解决事务并发的问题 悲观锁 乐观锁
    乐观锁
    1.Version方式(整数,存储空间小)
    // 添加一个私有字段Integer version,不由程序员维护,由JPA自己维护
    @Version
    private Integer version;
    StaleObjectStateException异常 说明乐观锁起作用了
    悲观锁

4.优化JPA的方式

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

JPA难在什么地方 -> 细节(练,思考)太多了,性能太难控制了(经验)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值