場景:
現在有這么一個情況,就是在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。
