我已经在我的项目中使用了Eclipselink很长一段时间,但今天我遇到了一个问题,我无法解决它。
问题在于:首先我搜索我的"功能"在我的程序实例中的对象,之后在另一个实例中我搜索并更改相同的记录(更改了" Interval"和" Date"列)并保存。在第一次实例中,我只更改" Interval",但在数据库中更改" Date"即使我没有改变,字段也已被更改,Eclipselink(在第一个实例中)在UPDATE中生成字段的更改"日期"只因为"功能"第一个实例的数据库已过时,而在此期间,在搜索对象和保存对象之间对注册表进行了更改。
在分析数据库中生成的查询时,我注意到Eclipselink在每次UPDATE之前生成一个SELECT,但在我的情况下我不需要它,我怎么能让Eclipselink只在UPDATE添加有变化的字段?而不是与数据库不同的那些。
我的Eclipselink配置:
"javax.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"
"javax.persistence.jdbc.url", "jdbc:mysql://{IP}:3306/{USER}?useTimezone=true&serverTimezone=America/Sao_Paulo&autoReconnect=true&zeroDateTimeBehavior=convertToNull"
"javax.persistence.jdbc.user", user
"javax.persistence.jdbc.password", password
"eclipselink.cache.shared.default", "false"
"eclipselink.logging.level", "WARNING"
"eclipselink.query-results-cache", "false"
"eclipselink.refresh", "true"
"eclipselink.weaving", "static"
"connection.autoReconnectForPools", "true"
"connection.autoReconnect", "true"
代码:
Function function = FunctionDAO.getFunctionByName("A");
function.setInterval(0);
...
EntityManager manager = {config};
manager.getTransaction().begin();
manager.merge(function);
manager.getTransaction().commit();
manager.close();
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "function")
public class Function extends ModelAudit implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String name;
@Column(name = "interval")
private Integer interval;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date")
private Date date;
...
getters and setters
答案 0 :(得分:1)
我不喜欢DAO对象,因为这个问题在使用查找/保存模式时很常见,为什么强烈建议使用乐观锁定。从您在实体中读取到调用save / merge的时间可能发生了任何数量的修改,如果您的方法被包装在自己的事务中并且只使用了em.merge(),那么您的实例会覆盖什么完全在数据库中。保留一个实体的时间越长,其他进程改变它的可能性就越大,并使您的数据副本过时。
选项:
使用某种形式的乐观锁定。在实体中阅读时, 它将具有版本控制,以便当你调用em.merge时 数据库中的版本超出了你传入的内容,它会给出 通知您潜在冲突的例外情况。
实现仅更新实体中字段选择的DAO changeValue方法。例如,setIntervalByName(String name,Integer interval)方法可以使用JPA更新查询来避免select,如果您不想读取实体,或者使用与getFunctionByName方法类似的相同功能。
使用both允许传递对象以进行复杂的更改,例如REST api可能会为get / put请求序列化实体,同时仍然允许优化以避免在实体图中读取其他地方的简单更改。