2015-11-29 29 views
1

我正在使用Spring Data(ver1.9) - JPA - EclipseLink(2.6.1) - Apache Tomcat。我想更新一個實體對象而不檢查它的存在。
例實體,使用Spring數據在eclipselink中執行沒有SELECT的更新

@Entity 
@Table(schema = "customSchema") 
public class Person implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(nullable = false) 
    private Integer id; 

    @Column(nullable = false, length = 60) 
    private String firstName; 

    public Person() { 
     this.id = null; 
     this.firstName = ""; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 
} 

示例性彈簧數據儲存庫,

@Repository 
public interface PersonRepository extends JpaRepository<Person, Integer> { 
} 

,我執行的代碼和所生成的SQL,

int id = 5; // This id is existing in my database. 
Person Person = personRepository.findOne(id); 
// SQL: One SELECT is executed. This is normal. 

person.setFirstName("aNewFirstName"); 

personRepository.saveAndFlush(person); 
// SQL: One SELECT is executed and then an update is executed. 

persistence.xml中,(層2高速緩存已禁用線程安全,it can be enabled selectively using @Cacheable annotation

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> 
    <persistence-unit name="my_peristenceUnit" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 
    <class>package.to.entity.Person</class> 
    <exclude-unlisted-classes>false</exclude-unlisted-classes> 
    <shared-cache-mode>NONE</shared-cache-mode> 
    </persistence-unit> 
</persistence> 

我的問題存在於saveAndFlush命令中。 EclipseLink正在檢查錶行中的字段,以使用SELECT sql命令確定其中哪些行已更改。這有助於創建僅包含編輯字段的更新命令。
刪除命令也一樣!

問題
有什麼辦法避免更新(saveAndFlush)的選擇SQL執行或刪除(刪除)命令?
如果我更喜歡更新表格的整行,該怎麼辦?不檢查哪些字段已經改變?

我已經看到另一個SO question類似於此,但此解決方案不適用於我的示例。我對Person Entity使用了@ExistenceChecking(value = ExistenceType.ASSUME_EXISTENCE)註釋,並且在執行saveAndFlush命令時沒有任何更改。

+0

您使用了哪些緩存選項?如果您執行查找或查詢,則應將對象讀入緩存中,因此不需要第二次選擇。您要調用的代碼應該使用同一個EntityManager進行兩次調用,以避免第二次讀取實體。 – Chris

+0

非常感謝您的評論。我編輯問題。我包含示例源代碼的persistence.xml。我沒有使用緩存。 –

+1

我不認爲這將無需緩存或使用某種擴展持久性單元,以便在find方法中使用的EntityManager與用於保存的EntityManager相同。他們是否在同一個交易環境中? – Chris

回答

1

EclipseLink有兩個不同的cache levels

第一個持久單元高速緩存。這是一個共享緩存(L2)或二層緩存。此緩存是您禁用的緩存,

<shared-cache-mode>NONE</shared-cache-mode> 

即使您禁用了它,也可以使用@Cacheable註釋顯式使用它。

第二持久性上下文緩存。這是爲EntityManager內的操作提供服務的獨立緩存(L1)。此緩存級別存在於您的應用程序中。這個緩存是避免EclipseLink提供者發生這種行爲的關鍵。

您可以調用兩次不同的存儲庫方法。爲了使用L1緩存,這個調用必須使用相同的EntityManager。在你的情況下,你正在使用不同的EntityManagers。下面的示例爲您的兩個不同的存儲庫調用使用相同的EntityManger。

@Service 
public class MyEnityService { 

    @Transactional 
    public Boolean create() { 
     int id = 5; // This id is existing in my database. 
     Person Person = personRepository.findOne(id); 
     // SQL: One SELECT is executed. This is normal AND CACHED FROM YOUR ENTITY MANAGER. 

     person.setFirstName("aNewFirstName"); 

     personRepository.saveAndFlush(person); 
     // SQL: ONLY ONE update is executed. NOTHING ELSE. 

     return true; 
    } 
} 

要當心,@Transactional註釋不工作在控制器的方法。你必須爲此使用服務。

相關問題