Невозможно сохранить данные с помощью объекта 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
и его семья.