This commit is contained in:
Struchkov Mark 2022-11-04 19:03:02 +03:00
parent 3c9b9267a5
commit 99dd506e4d
9 changed files with 166 additions and 22 deletions

View File

@ -27,9 +27,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>com.h2database</groupId>
<artifactId>postgresql</artifactId> <artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
@ -40,12 +39,12 @@
<dependency> <dependency>
<groupId>io.swagger.core.v3</groupId> <groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
<version>2.2.4</version> <version>2.2.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId> <artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.11</version> <version>1.6.12</version>
</dependency> </dependency>
</dependencies> </dependencies>

19
request/requests.http Normal file
View File

@ -0,0 +1,19 @@
### Получить первую страницу из 3 элементов
GET http://localhost:8080/api/post?offset=0&limit=3
Content-Type: application/json
### Получить вторую страницу из 3 элементов с сортировкой
GET http://localhost:8080/api/post/exampleSort?offset=1&limit=3&sort=createOn
Content-Type: application/json
### Получить вторую страницу из 3 элементов с сортировкой (enum)
GET http://localhost:8080/api/post/exampleEnumSort?offset=1&limit=3&sort=ID_ASC
Content-Type: application/json
### Получить вторую страницу из 3 элементов JPQL
GET http://localhost:8080/api/post/exampleJpql?offset=1&limit=3&title=Post
Content-Type: application/json
### Получить вторую страницу из 3 элементов SQL Native
GET http://localhost:8080/api/post/exampleSqlNative?offset=1&limit=3&title=Post
Content-Type: application/json

34
sql_examples.sql Normal file
View File

@ -0,0 +1,34 @@
EXPLAIN ANALYSE
SELECT *
FROM post
ORDER BY create_on
FETCH FIRST 50 ROWS ONLY;
EXPLAIN ANALYSE
SELECT *
FROM post
ORDER BY create_on
OFFSET 50 ROWS FETCH NEXT 50 ROWS ONLY;
EXPLAIN ANALYSE
SELECT *
FROM post
ORDER BY create_on
OFFSET 9950 ROWS FETCH NEXT 50 ROWS ONLY;
CREATE INDEX idx_post_created_on ON post (create_on DESC);
CREATE INDEX idx_post_created_on ON post (create_on DESC, id DESC);
EXPLAIN ANALYSE
SELECT *
FROM post
ORDER BY create_on DESC, id DESC
FETCH FIRST 50 ROWS ONLY;
EXPLAIN ANALYSE
SELECT *
FROM post
WHERE (create_on, id) < ('2022-10-30 00:11:43.224314', '8766d496-44c7-4e48-af29-b19178692cd9')
ORDER BY create_on DESC
FETCH FIRST 50 ROWS ONLY

View File

@ -1,9 +1,14 @@
package dev.struchkov.example; package dev.struchkov.example;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Component @Component
@ -12,14 +17,18 @@ public class GeneratorPost {
private final PostRepository postRepository; private final PostRepository postRepository;
public void generate() { @Transactional
@EventListener
public void generate(ContextRefreshedEvent event) {
final List<Post> posts = new ArrayList<>();
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
final Post post = new Post(); final Post post = new Post();
post.setId(UUID.randomUUID()); post.setId(UUID.randomUUID());
post.setTitle("Post " + i); post.setTitle("Post " + i);
post.setCreateOn(LocalDateTime.now().minusDays(1L).plusMinutes(i)); post.setCreateOn(LocalDateTime.now().minusDays(1L).plusMinutes(i));
postRepository.save(post); posts.add(post);
} }
postRepository.saveAll(posts);
} }
} }

View File

@ -3,30 +3,67 @@ package dev.struchkov.example;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Min;
@RestController @RestController
@RequestMapping("api/post") @RequestMapping("api/post")
@RequiredArgsConstructor @RequiredArgsConstructor
public class PostController { public class PostController {
private final PostRepository repository; private final PostRepository repository;
private final GeneratorPost generatorPost;
@GetMapping("generate")
public void generate() {
generatorPost.generate();
}
@GetMapping @GetMapping
public Page<Post> getAll( public Page<Post> getAll(
@RequestParam("offset") Integer offset, @RequestParam(value = "offset", defaultValue = "0") @Min(0) Integer offset,
@RequestParam("limit") Integer limit @RequestParam(value = "limit", defaultValue = "20") Integer limit
) { ) {
return repository.findAll(PageRequest.of(offset, limit)); return repository.findAll(PageRequest.of(offset, limit));
} }
@GetMapping("exampleSort")
public Page<Post> getAllAndSort(
@RequestParam("offset") Integer offset,
@RequestParam("limit") Integer limit,
@RequestParam("sort") String sortField
) {
return repository.findAll(
PageRequest.of(offset, limit, Sort.by(Sort.Direction.ASC, sortField))
);
}
@GetMapping("exampleEnumSort")
public Page<Post> getAllAndEnumSort(
@RequestParam("offset") Integer offset,
@RequestParam("limit") Integer limit,
@RequestParam("sort") PostSort sort
) {
return repository.findAll(
PageRequest.of(offset, limit, sort.getSortValue())
);
}
@GetMapping("exampleJpql")
public Page<Post> getAllJpql(
@RequestParam("title") String title,
@RequestParam("offset") Integer offset,
@RequestParam("limit") Integer limit
) {
return repository.findAllByTitleJpql(title, PageRequest.of(offset, limit));
}
@GetMapping("exampleSqlNative")
public Page<Post> getAllSqlNative(
@RequestParam("title") String title,
@RequestParam("offset") Integer offset,
@RequestParam("limit") Integer limit
) {
return repository.findAllByTitleNative(title, PageRequest.of(offset, limit));
}
} }

View File

@ -1,9 +1,25 @@
package dev.struchkov.example; package dev.struchkov.example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.UUID; import java.util.UUID;
public interface PostRepository extends JpaRepository<Post, UUID> { public interface PostRepository extends JpaRepository<Post, UUID> {
Page<Post> findAllByTitleLikeIgnoreCase(String titleLike, Pageable pageable);
@Query("SELECT p FROM Post p WHERE p.title like %:title%")
Page<Post> findAllByTitleJpql(@Param("title") String title, Pageable pageable);
@Query(
nativeQuery = true,
value = "SELECT * FROM POST WHERE TITLE LIKE %?1%",
countQuery = "SELECT count(*) FROM POST WHERE TITLE LIKE %?1%"
)
Page<Post> findAllByTitleNative(String title, Pageable pageable);
} }

View File

@ -0,0 +1,17 @@
package dev.struchkov.example;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
@Getter
@RequiredArgsConstructor
public enum PostSort {
ID_ASC(Sort.by(Sort.Direction.ASC, "id")),
ID_DESC(Sort.by(Sort.Direction.DESC, "id")),
DATE_ASC(Sort.by(Sort.Direction.ASC, "createOn"));
private final Sort sortValue;
}

View File

@ -1,8 +1,11 @@
package dev.struchkov.example; package dev.struchkov.example;
import org.h2.tools.Server;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.context.annotation.Bean;
import java.sql.SQLException;
@SpringBootApplication @SpringBootApplication
public class SpringPaginationApplication { public class SpringPaginationApplication {
@ -11,4 +14,9 @@ public class SpringPaginationApplication {
SpringApplication.run(SpringPaginationApplication.class, args); SpringApplication.run(SpringPaginationApplication.class, args);
} }
@Bean(initMethod = "start", destroyMethod = "stop")
public Server inMemoryH2DatabaseServer() throws SQLException {
return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092");
}
} }

View File

@ -1,13 +1,18 @@
spring: spring:
datasource: datasource:
driver-class-name: org.postgresql.Driver driver-class-name: org.h2.Driver
url: jdbc:postgresql://localhost:5432/test url: jdbc:h2:mem:demo
username: ${DB_USERNAME} username: sa
password: ${DB_PASSWORD} password: password
jpa: jpa:
hibernate: hibernate:
ddl-auto: update ddl-auto: create-drop
show-sql: true show-sql: true
properties: properties:
hibernate: hibernate:
format_sql: true format_sql: true
logging:
level:
org:
hibernate:
type: trace