Невозможно сохранить данные с помощью объекта Quarkus + Hibernate Reactive Panache

Я пытаюсь создать приложение Hello World с помощью Quarkus. У меня много проблем с тем, чтобы это работало.

Вот мои занятия:

      import java.time.Duration;

import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand;
import io.smallrye.mutiny.Uni;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Cacheable
@Entity
@Table(name = "category", schema = "administration")
@WithSessionOnDemand
public class Category extends PanacheEntityBase {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;
    public String name;

    public static Uni<Category > add(Category cat) {
        return Panache
                .withTransaction(cat::persist)
                .replaceWith(cat)
                .ifNoItem()
                .after(Duration.ofMillis(10000))
                .fail()
                .onFailure()
                .transform(t -> new IllegalStateException(t));
    }

}

      
   @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Uni<List<Category>> list2() {


        // Create and persist a new category
        Category category = new Category();
        category.name = "test quarkus 3";
        Category.add(category)
                .onItem().transform(id -> id.id)
                .subscribe().with(e -> System.out.println(e));


        // Return the list of categories
        return Category.listAll();
    }

Когда я нажимаю конечную точку GET, категория создается. Но если я нажму на него 3 раза подряд, я получу следующую ошибку: ERROR [io.qua.mut.run.MutinyInfrastructure] (vert.x-eventloop-thread-1) Mutiny had to drop the following exception: java.lang.IllegalStateException: java.lang.IllegalStateException: No current Mutiny.Session found - no reactive session was found in the context and the context was not marked to open a new session lazily - you might need to annotate the business method with @WithSession at org.test.category.Category.lambda$1(Category.java:39)

Поэтому я попытался аннотировать свои Categoryкласс с @WithSessionа потом с @WithSessionOnDemandно ничего не помогло. Что я делаю не так ?

2 ответа

тебе нужно связать свойcreateиqueryоперации в потоковом стиле, поэтому они могут получить доступ к сеансу из воздуха.

Класс сущности:

      import jakarta.persistence.Cacheable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;

import io.quarkus.hibernate.reactive.panache.PanacheEntity;

@Entity
@Cacheable
public class Fruit extends PanacheEntity {

  @Column(length = 40, unique = false)
  public String name;

}

Класс обслуживания:

      import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import java.time.Duration;
import java.util.List;

// first method
@Path("/fruits")
@ApplicationScoped
public class FruitResource {

  @GET
  public Uni<List<Fruit>> get() {
    return Fruit.listAll(Sort.by("name"));
  }

  @POST
  public Uni<List<Fruit>> create(Fruit fruit) {

    Uni<Long> createStage = Panache
        .withTransaction(fruit::persist)
        .replaceWith(fruit)
        .ifNoItem()
        .after(Duration.ofMillis(10000))
        .fail()
        .onFailure()
        .transform(t -> {
          System.out.println("exception happen lalal");
          t.printStackTrace();
          return new IllegalStateException(t);
        })
        .onItem().transform(item -> {
          System.out.println("fruit is created: " + item.id);
          return item.id;
        });
    Uni<List<Fruit>> queryAllFruitsStage = Fruit.listAll();

    return createStage.chain(() -> queryAllFruitsStage);

  }
}

// second method
@Path("/fruits")
@ApplicationScoped
public class FruitResource {

  @GET
  public Uni<List<Fruit>> get() {
    return Fruit.listAll(Sort.by("name"));
  }

  @POST
  public Uni<List<Fruit>> create(Fruit fruit) {

    return Panache
        .withTransaction(fruit::persist)
        .replaceWith(fruit)
        .ifNoItem()
        .after(Duration.ofMillis(10000))
        .fail()
        .onFailure()
        .transform(t -> {
          System.out.println("exception happen lalal");
          t.printStackTrace();
          return new IllegalStateException(t);
        })
        .onItem()
        .transformToUni(item -> Fruit.listAll());
  }
}

Тест на завиток:

      curl --location 'localhost:8080/fruits' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
    "name": "fruit1"
}'

вы можете взглянуть на часть Mutiny Patterns в документации Quarkus - Mutiny Primer и лучше понять реактивное программирование.

Я столкнулся с аналогичной проблемой: приложение hello world вам может не понадобиться.

Вы можете проверить, как команда Quarkus использует его в своем демонстрационном приложении quarkus-super-heroes.

Вы также можете проверить, как о проблеме, с которой вы столкнулись, было сообщено в той же проблеме с приложением, здесь , а также комментарии команды.


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

Category.java (как и у вас, я не использую схему администрирования, вот и все)

      @Cacheable
@Entity
@Table(name = "category")
public class Category extends PanacheEntityBase {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;

  public static Uni<Category> add(Category cat) {
    return Panache
        .withTransaction(cat::persist)
        .replaceWith(cat)
        .ifNoItem()
        .after(Duration.ofMillis(10000))
        .fail()
        .onFailure()
        .transform(IllegalStateException::new);

/*get/set omitted for brevity*/
  }

CategoryResource.java (ваш контроллер)

      @Path("/category")
@Produces(MediaType.APPLICATION_JSON)
public class CategoryResource {
  @GET
  public Uni<List<Category>> listAllCategories() {
    Category category = new Category();
    category.setName("name");

    return Category.add(category)
        .replaceWith(Category.findAll().list());
  }

  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  public Uni<List<Category>> createCategory(final Category category) {
    return Category.add(category)
        .replaceWith(Category.findAll().list());
  }
}

Я взял на себя смелость добавить метод POST.

Здесь у вас есть репозиторий GitHub с быстрым рабочим примером → SO-cannot-persist-data-with-quarkus-hibernate-reactive-panache-entity


Для базы кода, превышающей учебный пример, вам может понадобиться@WithSessionи его семья.


снимок экрана кода и вызова REST

Другие вопросы по тегам