在具有 Spring 数据的 eclipselink 中执行没有 SELECT 的更新
Perform UPDATE without SELECT in eclipselink with Spring Data
我正在使用 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 数据存储库,
@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 命令检查 table 行中的字段以确定其中哪些字段已更改。这有助于创建仅包含已编辑字段的更新命令。
删除命令也是如此!
问题
有什么方法可以避免select sql update(saveAndFlush) 或delete(delete) 命令的执行吗?
如果我更喜欢更新 table 的整行怎么办?不检查哪些字段已更改?
我见过另一个与此类似的 SO question,但此解决方案不适用于我的示例。我对 Person 实体使用了 @ExistenceChecking(value = ExistenceType.ASSUME_EXISTENCE) 注释,执行 saveAndFlush 命令时没有任何变化。
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;
}
}
小心,@Transactional 注释不适用于控制器方法。您必须为此使用服务。
我正在使用 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 数据存储库,
@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 命令检查 table 行中的字段以确定其中哪些字段已更改。这有助于创建仅包含已编辑字段的更新命令。
删除命令也是如此!
问题
有什么方法可以避免select sql update(saveAndFlush) 或delete(delete) 命令的执行吗?
如果我更喜欢更新 table 的整行怎么办?不检查哪些字段已更改?
我见过另一个与此类似的 SO question,但此解决方案不适用于我的示例。我对 Person 实体使用了 @ExistenceChecking(value = ExistenceType.ASSUME_EXISTENCE) 注释,执行 saveAndFlush 命令时没有任何变化。
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;
}
}
小心,@Transactional 注释不适用于控制器方法。您必须为此使用服务。