我正在使用Spring Data(ver1.9) - JPA - EclipseLink(2.6.1) - Apache Tomcat。我想更新一个实体对象,而不检查它是否存在 示例实体,
@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;
}
}
示例Spring Data Repository,
@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命令更改了哪些字段。这有助于创建仅包含已编辑字段的更新命令 删除命令也是如此!
问题
有没有办法避免select sql执行更新(saveAndFlush)或删除(删除)命令?
如果我更喜欢更新表格的整行,该怎么办?不检查哪些字段已更改?
我见过另一个SO question与此相似,但这个解决方案并不适合我的例子。我对Person Entity使用了@ExistenceChecking(value = ExistenceType.ASSUME_EXISTENCE)注释,并且在执行saveAndFlush命令时没有任何改变。
答案 0 :(得分:1)
EclipseLink有两个不同的cache levels。
第一个是持久性单元缓存。这是共享缓存(L2)或第2层缓存。此缓存是您禁用的缓存,
<shared-cache-mode>NONE</shared-cache-mode>
即使您禁用它,也可以使用@Cacheable注释显式使用它。
第二个是持久性上下文缓存。这是一个隔离缓存(L1),用于为EntityManager中的操作提供服务。此缓存级别存在于您的应用程序中。此缓存是避免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;
}
}
小心,@ Transactal注释不适用于Controller方法。你必须为此使用服务。