zoukankan      html  css  js  c++  java
  • 【spring data jpa】使用spring data jpa时,关于service层一个方法中进行【删除】和【插入】两种操作在同一个事务内处理

    场景:

    现在有这么一个情况,就是在service中提供的一个方法是先将符合条件的数据全部删除,然后再将新的条件全部插入数据库中

    这个场景需要保证service中执行两步

    1.删除

    2.插入 

    这两步自然是在同一个事务中完成才是一个完整的操作。

    那么针对这个场景,看看注解怎么用

    1》》先看dao层 链接:http://www.cnblogs.com/sxdcgaq8080/p/8984140.html

    dao层也就是repository层的delete操作,也就是在jpa中使用delete操作,需要加上

    @Modifying
    @Transactional

    这两个注解,因为

    1.@Modifying 以通知 SpringData, 这是一个 UPDATE 或 DELETE 操作

    2.UPDATE 或 DELETE 操作需要使用事务,所以在dao层的delete方法上需要加上这两个注解

    2》》然后说service层的这个方法中的两步走

    需要在入口方法上加上

    @Transactional

    注解,用来保证两步操作在同一个事务内执行

    这样的情况,是第一个事务注解起作用,delete方法上的注解是为了支持delete操作才加的

    ======================================

    但是这个时候依旧是会出问题的,因为执行spring data的delete操作,并不会立即执行,而是等到service方法执行完成,才会提交事务。但是这样的话 insert插入就会出现 重复数据存在,不能重复插入的错误!!!

    理一下这个逻辑:【spring的事务@Transactional底层是spring AOP】

      1.进入方法,开启事务

      2.代码delete方法是jpa的delete方法,断点在此处发现并没有执行delete的sql语句,但是执行了一条select语句。【可见自定义的delete方法是根据查到的数据再拼接sql在事务提交的时候才执行】

      3.执行save的插入方法,执行了insert语句,报错数据已经存在,不能重复插入

      4.关闭事务

    而我们想要delete在insert之前就执行了,并且还要保证delete和insert是在同一个事务中进行的。

    解决方案1:

    仅更改service代码

    手动调用flush()方法,【让jpa在selete出这个对象之后,拼接了delete语句,然后即刻执行sql作用到数据库】,这样在下面insert的时候delete已经执行了,就不会出现重复数据的错误。

    解决方法2:

    就是写@Query("JPQL语句")

    告诉jpa,我要明确执行这条delete的sql语句,避免了【让它去查一遍,拿到实体以后再拼接SQL语句,最后在方法结束,事务提交的时候才去执行delete语句】,这个时候已经迟了。

    这个时候是不会执行select语句的,只执行了delete和insert

    仅改变dao层代码

     service不变如下

    这两种方式都可以解决 delete操作和save操作在同一个事务中的原子性。

    但是第一种方法相当于是多做了一步,就是执行delete的时候会去数据库selete一次。。。而第二种方法则会直接执行delete语句,不会执行selete。

  • 相关阅读:
    宏的全解
    Mathematica 表达式求值
    nandflash中oob、ecc分析
    ubuntu 12.04下安装openldap,slapd.conf找不到的解决方法
    jetbrains
    看看美国公务员挣多少钱
    css的#和.的区别
    Ubuntu 14.04 LTS下安装Google Chrome浏览器
    Bootstrap 模态框(Modal)插件
    怎么旋转PDF文件的方向并保存成功
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/8985662.html
Copyright © 2011-2022 走看看