Параллелизм и поведение репозитория JPA

#java #multithreading #spring-boot #hibernate #jpa

Вопрос:

У меня есть 2 объекта, сопоставленные с JPA

 @Entity
class Table_A {

  @Id
  private Integer id;

  @Enumerated(EnumType.STRING)
  private ModuleType module;

  private String name;

  private Instant lastModifiedDate; 

  private String creator;

  @NotNull
  @Enumerated(EnumType.STRING)
  private State state;
  
  @OneToMany(fetch = FetchType.LAZY)
    @JoinColumns( value = {
      @JoinColumn(name="id_object", referencedColumnName = "id_entity", insertable = false, updatable = false),
      @JoinColumn(name="object_sub_type", referencedColumnName = "object_sub_type", insertable = false, updatable = false),
  }, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
  private List<AttributeValue> attributes;
}


@Entity
Class Table B {
@Id
  private Integer id;

  @Column(name = "id_create_user", insertable = false, updatable = false)
  private String createUser;

  @Column(name = "type_object", insertable = false, updatable = false)
  private String typeObject;


  @Column(name = "id_object", insertable = false, updatable = false)
  private Integer idTable_A;

  @Column(name = "name")
  private String name;

  private Boolean hasCombination;
}
 

Эти сущности не связаны между собой. А также у меня есть интерфейс JpaRepository для каждого из них.

 @Repository
public interface Table_A_Repository extends JpaRepository<Table_A, Integer>
@Repository
public interface Table_B_Repository extends JpaRepository<Table_B, Integer>
 

Когда у меня есть 2 темы.

Первый Thread_1 считывает объект «Table_A», выполняет некоторые операции и изменяет одно поле объекта table_A

Второй Thread_2 считывает тот же объект из Table_A и вносит изменения в разные строки Table_B ( Table_B_Repository.saveAll( listOfTable_Bobjects) ) до завершения Thread_1.

Я вижу, что than Thread_2 переопределяет изменение Thread_1 в объекте Table_A.

Чего я не понимаю, так это почему вызов Table_B_Repository.saveAll делает и обновляет в table_A переопределяет значение, установленное в первом потоке, оставляя его таким, каким оно было.

спасибо за ваши ответы или комментарии.

Ответ №1:

Проблема с этой реализацией заключается в том, что при попытке обновления методом saveall у вас будут все данные в объектах.

Поэтому, если вы читаете данные по имени, то для некоторого имени существует около 4 объектов, и вы обновляете только последний объект, но во время сохранения вы сохраняете не только этот объект, но и все объекты, которые вы прочитали ранее.

В режиме гибернации, если в данных произошли какие-либо изменения, только это приведет к обновлению данных в базе данных, поэтому объекты, которые были обновлены потоком A, будут рассматриваться для обновления потоком B, и все изменения, внесенные потоком A, будут переопределены.

Комментарии:

1. но разве Table_B_Repository не должен обновлять только объекты, связанные с Table_B ? Меня это немного смущает. Будет способ добиться только обновления элементов table_B.

2. можете ли вы поделиться своим кодом репозитория и кодом сущности здесь.

3. Я только что обновил информацию о сущностях @Pirate

4. можете ли вы также поделиться кодом для потока B? Также вы можете проверить, обновляет ли поток A значение или нет. Глядя на вашу сущность, она не должна обновляться, как вы упомянули в вопросе.

5. Из того, что я понимаю, Jparepository обновляет только свой класс, связанный с ним, и возможные отношения этого класса(много всего…..), верно? Я не могу поделиться кодом, потому что он огромен и имеет множество связанных классов (устаревший код), но я уверен, что Table_B не имеет никакого отношения к базе данных.

Ответ №2:

Метод saveAll в репозитории сохранит запись, если она новая, и объединит, если она не новая. Поэтому, если вы сохраните все записи, записи, измененные потоком 1, будут перезаписаны в контексте сохранения путем слияния().