Quarkus学习
指令式与响应式
1.线程的问题
- 在传统的指令式方法中,框架分配一个线程来处理请求。因此,请求的整个处理都运行在这个工作线程上。这个模型的扩展性不太好。事实上,要处理多个并发请求,你需要多个线程。因此,应用程序的并发性受到线程数量的限制。此外,只要您的代码与远程服务交互,这些线程就会被阻塞。因此,这会导致资源的低效使用,因为您可能需要更多的线程,而每个线程在映射到OS线程时,在内存和CPU方面都有成本。
- 响应式模型依赖于非阻塞 I/O和不同的执行模型。非阻塞I/O提供了一种处理并发I/O的有效方法。最小数量的线程称为I/O线程,可以处理许多并发I/O。使用这样的模型,请求处理不会委托给工作线程,而是直接使用这些I/O线程。它节省了内存和CPU,因为不需要创建工作线程来处理请求。它还改善了并发性,因为它消除了对线程数量的限制。最后,它还改善了响应时间,因为它减少了线程开关的数量。
Uni<PanacheEntityBase> findById = Fruit.findById(id);
Uni<Fruit> findById2 = Fruit.<Fruit>findById(id);
Fruit
继承 PanacheEntityBase
指定返回类型为Fruit
quarkus中使用panache reactive工具使用原生sql查询
- 在实体类上使用注解
@NamedNativeQueries
@NamedNativeQueries({
@NamedNativeQuery(name = "Cat.findByName", query = "select * from cat where name = :name ", resultClass = Cat.class)
})
- 需要在repository中使用sessionFactory调用命名查询
@Inject
Mutiny.SessionFactory sessionFactory;
/**
* 命名查询,使用原生SQL
*
* @param name 姓名
* @return Uni<List<Cat>> 单项流
*/
public Uni<List<Cat>> findCat(String name) {
return sessionFactory.withSession(session -> session.createNamedQuery("Cat.findByName", Cat.class)
.setParameter("name", name).getResultList());
}
- 或者创建原生语句(此处使用文本块)
/**
* 编写原生SQL语句
*
* @param id id
* @return Uni<List < Cat>>
*/
public Uni<List<Cat>> findByName(Long id) {
return sessionFactory.withSession(session -> session.createNativeQuery(
"""
SELECT c.*
FROM Cat c
join person p
on c.person_id=p.id
WHERE c.id = :id""", Cat.class)
.setParameter("id", id).getResultList()
);
}
获取请求信息的问题
- 使用
@Context
注入上下文对象
@Context
HttpServerRequest request;// 注意导包是 io.vertx.core.http.HttpServerRequest;而不是multy下的
@Context
UriInfo uriInfo;
LOGGER.info("RequestMethod: " + request.method());
LOGGER.info("URL: " + uriInfo.getPath());
LOGGER.info("IP: " + request.remoteAddress());
事务例子
- 事务已用
Panache.WithTransaciton()
开启,Uni的组合流会报错,不明原因。可转Multi后组合,但是不再是单项流了,另一种解决方法是使用transformToUni()
进行转换,但会嵌套。
public Multi<Boolean> update(Account source, Account target) {
Multi<Boolean> multi = sessionFactory.withSession((session) -> session.find(Account.class, source.id))
.map(Objects::nonNull).toMulti();
Multi<Boolean> multi1 = sessionFactory.withSession((session) -> session.find(Account.class, target.id))
.map(Objects::nonNull).toMulti();
return Multi.createBy().combining().streams(multi1, multi).asTuple().map(tuple -> tuple.getItem1() && tuple.getItem2());
}
public static Uni<Boolean> transactionMoney(Account source, Account target) {
Uni<Boolean> sourceSelect = findById(source.id)
.map(Objects::nonNull);
Uni<Boolean> targetSelect = findById(target.id)
.map(Objects::nonNull);
return sourceSelect.onItem().transformToUni(x ->
x ? targetSelect : Uni.createFrom().item(false)
).onItem().transformToUni(flag -> {
if (flag) {
return update("set money=money-50 where id=?1", source.id).onItem().transformToUni(n -> {
if (n > 0) {
return update("set money=money+50 where id=?1", target.id).map(result -> result > 0);
}
return Uni.createFrom().item(false);
});
}
return Uni.createFrom().item(() -> false);
});
}