Как сделать update вместе insert в Spring Data?

358
29 июня 2017, 02:05

У меня имеется такая вот сущность:

@Data
@Entity
public class Message {
    @Id
    private long id;
    private String recipient;
    private String subject;
    private String text;
    private boolean sent;
    private String status;
    @Column(name = "expire")
    @CreationTimestamp
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private Date expire;
    @Column(name = "updated_at")
    @CreationTimestamp
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private Date updatedAt;
    @Column(name = "created_at")
    @CreationTimestamp
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private Date createdAt;
    @PreUpdate
    protected void onUpdate() {
        updatedAt = new Date();
    }
}

И такой тестовый контроллер:

@RestController
public class MessageTestController {
    @Autowired
    private MessageService messageService;

    @RequestMapping("/testMessage")
    public Message testMessage(@RequestBody Message message) {
        System.out.println(message.getId());
        System.out.println(message.getRecipient());
        System.out.println(message.getStatus());
        System.out.println(message.getSubject());
        messageService.save(message);
        return messageService.findById(0);
    }
}

Проблема в том, при отправке контроллеру json в таком формате

{
    "id": 0,
    "recipient": "samoilov.s@natalie-tours.ru",
    "subject": "some subject",
    "text": null,
    "sent": false,
    "status": "NOT NOW 2",
    "expire": "2017-06-27 09:42:41",
    "updatedAt": "2017-06-27 09:48:27",
    "createdAt": "2017-06-27 09:42:41"
}

возникает такая ошибка

ERROR: duplicate key value violates unique constraint "message_pkey"

Но если я сделаю messageService.findById(0) и потом save полученного элемента, то update произойдет успешно. Почему так ?

Если над id поставить аннотацию @GeneratedValue(strategy=GenerationType.IDENTITY), то будет происходить insert новых записей с новым id, но не update. При этом в json я передаю id напрямую.

Answer 1

когда Вы делаете сначала messageService.save(message);, то объект message неперсистный, а new (или Transient) и HIBERNATE полагает, что Вы создали новый объект и в БД его нет. Поэтому Hibernate делает insert. Он не делает предварительную проверку есть ли объект с ID=0 в БД. А когда Вы сначала сделаете find, то HIBERNATE создаст в кэше персистный объект с ID=0 и при save будет понимать, что объект с id=0 уже есть и надо делать update.

Попробуйти использовать утилиту, для просмотра содержимого кэша перед и после вызовов этих двух методов в разных порядках.

Содержимое кэша

READ ALSO
Ошибка кодировки

Ошибка кодировки

При создании записи в БД через crud-приложение java кириллические символы в таблице юзеров (crud по юзерам) и в БД (в MySQLWorkbench) отображаются приблизительно...

352
Как найти ссылки в тексте? И их положение

Как найти ссылки в тексте? И их положение

ЗдравствуйтеЕсть текст моя программа делит его на предложения

299
DataSource в Intellij IDEA

DataSource в Intellij IDEA

В Intellij IDEA есть вкладка DatabaseВ ней можно добавить DataSource

394
Полоса прокрутки в datalist

Полоса прокрутки в datalist

Есть список реализован с помощью datalist

312