通过分页提高NoSQL查询的性能

本文探讨了在Jakarta EE上使用Jakarta NoSQL进行分页以提高数据库查询性能的重要性。通过实例展示了如何在MongoDB上进行分页操作,强调了分页对于减少内存、数据库和网络资源浪费的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章分享自国内优秀IT教育机构——【优锐课】。我们将讨论如何使用新规范Jakarta NoSQL在Jakarta EE上进行分页。
在这里插入图片描述
分页是将内容分成离散页面的过程。每个页面都有来自数据库的实体列表。分页允许从数据存储中检索大量元素到小块中,例如,它返回十页包含一百个项目,而不是在存储引擎中返回一千个。这篇文章将讨论如何使用新规范Jakarta NoSQL在Jakarta EE上进行分页。

这篇文章将结合使用MongoDB和Car实体来演示如何在Jakarta NoSQL API上进行分页。

服务器启动时,MongoDB数据库必须正在运行,因此你可以手动下载并安装它,也可以使用Docker映像,然后运行以下命令:

docker run -d --name mongodb-instance -p 27017:27017 mongodb

该项目是一个Java SE项目,具有通过maven运行的CDI 2.0和Jakarta NoSQL。因此,所有配置和依赖项都是pom.xml文件。Jakarta NoSQL项目已获得批准,但不是最终版本。因此,该示例使用SNAPSHOT版本。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <name>Artemis Demo using Java SE MongoDB with pagiantion</name>
    <groupId>org.jnosql.artemis</groupId>
    <artifactId>pagination</artifactId>
    <version>0.1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.jnosql.artemis</groupId>
            <artifactId>artemis-document</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jnosql.diana</groupId>
            <artifactId>mongodb-driver</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.weld.se</groupId>
            <artifactId>weld-se-shaded</artifactId>
            <version>${weld.se.core.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse</groupId>
            <artifactId>yasson</artifactId>
            <version>${json.b.version}</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>oss.sonatype.org-snapshot</id>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

Car 实体具有五个属性:id,provider,model,year和color。

import jakarta.nosql.mapping.Column;
import jakarta.nosql.mapping.Entity;
import jakarta.nosql.mapping.Id;
@Entity
public class Car {
    @Id
    private Long id;
    @Column
    private String provider;
    @Column
    private String model;
    @Column
    private Integer year;
    @Column
    private String color;
    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", provider='" + provider + '\'' +
                ", model='" + model + '\'' +
                ", year=" + year +
                ", color='" + color + '\'' +
                '}';
    }
}

我们将使用Mockaroo生成汽车信息,然后将此JSON转换为Jakarta NoSQL插入查询。

insert Car {"_id":1,"provider":"Dodge","model":"Caravan","year":2006,"color":"Teal"}
insert Car {"_id":2,"provider":"Lamborghini","model":"Aventador","year":2012,"color":"Blue"}
insert Car {"_id":3,"provider":"Mitsubishi","model":"Pajero","year":1997,"color":"Green"}
insert Car {"_id":4,"provider":"Mazda","model":"Miata MX-5","year":2005,"color":"Mauv"}
insert Car {"_id":5,"provider":"Dodge","model":"Aries","year":1981,"color":"Blue"}
insert Car {"_id":6,"provider":"Ford","model":"Windstar","year":1995,"color":"Yellow"}
insert Car {"_id":7,"provider":"Subaru","model":"Impreza","year":1999,"color":"Purple"}
insert Car {"_id":8,"provider":"Plymouth","model":"Acclaim","year":1995,"color":"Khaki"}
insert Car {"_id":9,"provider":"Audi","model":"200","year":1990,"color":"Puce"}
insert Car {"_id":10,"provider":"Kia","model":"Spectra","year":2009,"color":"Crimson"}
insert Car {"_id":11,"provider":"Volkswagen","model":"Golf","year":2001,"color":"Crimson"}
insert Car {"_id":12,"provider":"Chevrolet","model":"Silverado 1500","year":2008,"color":"Indigo"}
insert Car {"_id":13,"provider":"Studebaker","model":"Avanti","year":1961,"color":"Turquoise"}
insert Car {"_id":14,"provider":"Audi","model":"100","year":1994,"color":"Purple"}
insert Car {"_id":15,"provider":"Ford","model":"Taurus","year":2003,"color":"Maroon"}
insert Car {"_id":16,"provider":"GMC","model":"Acadia","year":2010,"color":"Indigo"}
insert Car {"_id":17,"provider":"Toyota","model":"Camry Hybrid","year":2011,"color":"Violet"}
insert Car {"_id":18,"provider":"Buick","model":"Roadmaster","year":1996,"color":"Purple"}
insert Car {"_id":19,"provider":"Mercury","model":"Monterey","year":2006,"color":"Mauv"}
insert Car {"_id":20,"provider":"GMC","model":"Sierra","year":2010,"color":"Violet"}

我们将有一个查询提供程序,它读取NoSQL文件并返回查询列表。

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
@ApplicationScoped
class QuerySupplier implements Supplier<List<String>> {
    private List<String> queries;
    @PostConstruct
    void init() throws IOException {
        final URL resource = QuerySupplier.class.getClassLoader().getResource("cars.nosql");
        this.queries = Files.readAllLines(Paths.get(resource.getFile()));
    }
    @Override
    public List<String> get() {
        return Collections.unmodifiableList(queries);
    }
}

在第一个示例代码中,我们将插入查询,然后从数据库中选择所有查询。二十个元素是一个很小的数目,但是此查询对性能有危险。确实,使用相同的查询可能会返回数千。几个数据库设置了默认限制,例如Cassandra,它隐式定义了上万个元素。一万个仍然是一个庞大的数字,要么显示给用户,要么返回到REST应用程序中。因此,这浪费了内存,数据库和网络。

import jakarta.nosql.mapping.document.DocumentTemplate;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Supplier;
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
public class App {
    public static void main(String[] args) throws IOException {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            DocumentTemplate template = container.select(DocumentTemplate.class).get();
            Supplier<List<String>> querySupplier = container.select(QuerySupplier.class).get();
            template.delete(delete().from("Car").build());
            final List<String> queries = querySupplier.get();
            queries.forEach(template::query);
            final List<Car> cars = template.query("select * from Car order by provider asc");
            System.out.println(cars.size());
        }
    }
    private App() {
    }
}

在Jakarta NoSQL,有一个表示分页的接口。有分页界面。

Pagination pagination = Pagination.page(1).size(2);
//it creates a pagination instance where it is the first page and each page has the size of two each one.
long pageNumber = pagination.getPageNumber();
Pagination next = pagination.next();

每个NoSQL API在允许分页的查询中都有专门的查询,例如DocumentQueryPagination和ColumnQueryPagination。因此,Java开发人员可以定义每个请求要返回的值的数量。

import jakarta.nosql.document.DocumentQuery;
import jakarta.nosql.mapping.Page;
import jakarta.nosql.mapping.Pagination;
import jakarta.nosql.mapping.document.DocumentQueryPagination;
import jakarta.nosql.mapping.document.DocumentTemplate;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import java.util.List;
import java.util.function.Supplier;
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
public class App2 {
    public static void main(String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            DocumentTemplate template = container.select(DocumentTemplate.class).get();
            Supplier<List<String>> querySupplier = container.select(QuerySupplier.class).get();
            template.delete(delete().from("Car").build());
            final List<String> queries = querySupplier.get();
            queries.forEach(template::query);
            DocumentQuery query = DocumentQuery.select().from("Car").orderBy("provider").asc().build();
            Pagination pagination = Pagination.page(1).size(2);
            DocumentQueryPagination queryPagination = DocumentQueryPagination.of(query, pagination);
            final Page<Car> page = template.select(queryPagination);
            List<Car> cars = page.getContent();
            System.out.println(cars.size());
            final Page<Car> nextPage = page.next();
            cars = nextPage.getContent();
            System.out.println(cars.size());
        }
    }
    private App2() {
    }
}

结果是一个Page实例,在该实例中有一种方法可以返回下一页,因此可以返回以下内容。存储库接口还支持将值作为Page实例返回。

import jakarta.nosql.mapping.Page;
import jakarta.nosql.mapping.Pagination;
import jakarta.nosql.mapping.Repository;
import java.util.List;
public interface CarRepository extends Repository<Car, Long> {
    List<Car> findByOrderByProvider(Pagination pagination);
    Page<Car> findAll(Pagination pagination);
}
import jakarta.nosql.mapping.Page;
import jakarta.nosql.mapping.Pagination;
import jakarta.nosql.mapping.document.DocumentTemplate;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import java.util.List;
import java.util.function.Supplier;
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
public class App3 {
    public static void main(String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            DocumentTemplate template = container.select(DocumentTemplate.class).get();
            CarRepository repository = container.select(CarRepository.class).get();
            Supplier<List<String>> querySupplier = container.select(QuerySupplier.class).get();
            template.delete(delete().from("Car").build());
            final List<String> queries = querySupplier.get();
            queries.forEach(template::query);
            Pagination pagination = Pagination.page(1).size(2);
            final Page<Car> page = repository.findAll(pagination);
            List<Car> cars = page.getContent();
            System.out.println(cars.size());
            final Page<Car> nextPage = page.next();
            cars = nextPage.getContent();
            System.out.println(cars.size());
        }
    }
    private App3() {
    }
}

至关重要的一点是,开发人员可以将分页和Collection结合在一起,结果将使用该分页进行查询。

import jakarta.nosql.mapping.Pagination;
import jakarta.nosql.mapping.document.DocumentTemplate;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import java.util.List;
import java.util.function.Supplier;
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
public class App4 {
    public static void main(String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            DocumentTemplate template = container.select(DocumentTemplate.class).get();
            CarRepository repository = container.select(CarRepository.class).get();
            Supplier<List<String>> querySupplier = container.select(QuerySupplier.class).get();
            template.delete(delete().from("Car").build());
            final List<String> queries = querySupplier.get();
            queries.forEach(template::query);
            Pagination pagination = Pagination.page(1).size(2);
            final List<Car> cars = repository.findByOrderByProvider(pagination);
            System.out.println(cars.size());
        }
    }
    private App4() {
    }
}

在本文中,我们介绍了分页的概念,并解释了为什么当开发人员谈论性能时,分页对NoSQL数据库如此重要。
感谢阅读!在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值