#postgresql #spring-boot #jpa
#postgresql #spring-загрузка #jpa
Вопрос:
Я столкнулся со странной проблемой, дата последнего изменения не обновляется автоматически. Я использую Postgresql версии 12.3 и Springboot 2.2.4.RELEASE Вот мой класс сущности
@Entity
@Table(name = "users")
@org.hibernate.annotations.Entity(
dynamicUpdate = true
)
@Data
public class Users {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
@Column(updatable = false, nullable = false)
private String userId;
private String userName;
private String userEmail;
private String userPhoneNumber;
@CreationTimestamp
@Column(updatable = false)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT 05:30")
private Timestamp createdOn;
@UpdateTimestamp
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT 05:30")
private Timestamp lastUpdatedOn;
}
Записи базы данных:
createdon | lastupdatedon
2020-08-27 07:43:37.994 | 2020-08-27 07:43:37.994
2020-08-07 07:49:22.797 | 2020-08-07 07:49:22.797
2020-08-12 13:38:43.503 | 2020-08-12 13:38:43.503
Вы можете видеть, что CreatedOn и lastUpdatedOn одинаковы. Несмотря на то, что записи часто обновляются, дата последнего изменения не обновляется.
Я сохраняю запись в репозитории jpa, например:
usersRepository.save(user);
Комментарии:
1. И как вы обновляете эти записи.
2. использование методов jpa, таких как usersRepository.save(user);
3. Одну вещь вы пробовали без специфики гибернации
dynamicUpdate
? Просто интересно. Также вы не обновляете что-то с помощью запроса где-нибудь (поскольку это обходит слушателей).4. @M.Deinum Я попытался обновить запись напрямую с помощью CLI (psql), даже с последней даты, которая не изменилась.
5. Конечно, это не изменится, если вы напрямую запустите SQL. Это особенность Spring Data JPA, поэтому, если вы обойдете это, это ничего не даст.
Ответ №1:
Можете ли вы попробовать использовать аннотацию prePersist amp; preUpdate вместо CreationTimestamp amp; UpdateTimestampas, чтобы иметь больше контроля над объектом и применить ниже-
@Entity
@Table(name = "users")
@org.hibernate.annotations.Entity(
dynamicUpdate = true
)
@Data
public class Users {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
@Column(updatable = false, nullable = false)
private String userId;
private String userName;
private String userEmail;
private String userPhoneNumber;
@Column(updatable = false)
private Timestamp createdOn;
@Column
private Timestamp lastUpdatedOn;
@PrePersist
public void onInsert() {
createdOn = Timestamp.from(ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
lastUpdatedOn = createdOn;
}
@PreUpdate
public void onUpdate() {
lastUpdatedOn = Timestamp.from(ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
}
}
Комментарии:
1. Под капотом это то, что в конечном итоге будет использоваться, хотя и через прослушиватель.
Ответ №2:
Вы случайно вызываете метод сохранения в транзакции?
Временные метки заполняются при записи в БД, поэтому вы не увидите их значения до тех пор, пока транзакция не будет зафиксирована.
Когда я столкнулся с этой проблемой, у меня был код, который выглядел следующим образом:
@Transactional
public Response createFooBusinessLogic(Foo foo) {
var createdEntity = fooRepository.save(foo);
return someMethodUsingCreatedTime(createdEntity);
}
Есть два решения:
- Если даты требуются другому объекту в транзакции БД, вы можете использовать
saveAndFlush
вместоsave
. Это приводит к принудительной записи в БД, возвращая обратно созданные и измененные даты. - В противном случае преобразуйте
save
вызов в другой метод и аннотируйте этот метод с@Transactional
помощью .
Я выбрал вариант (2), который выглядел так:
public Response createFooBusinessLogic(Foo foo) {
var createdEntity = facade.saveFoo(foo);
return someMethodUsingCreatedTime(createdEntity);
}
// In Facade.java
@Transactional
public Foo saveFoo(Foo foo) {
return fooRepository.save(foo);
}
Обратите внимание, что для работы аннотации транзакции вызов не должен быть самозапускающимся (т. е. должен вызываться в другом классе), и метод должен быть общедоступным.