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>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
@ -40,12 +39,12 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.4</version>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.11</version>
<version>1.6.12</version>
</dependency>
</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;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Component
@ -12,14 +17,18 @@ public class GeneratorPost {
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++) {
final Post post = new Post();
post.setId(UUID.randomUUID());
post.setTitle("Post " + 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 org.springframework.data.domain.Page;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Min;
@RestController
@RequestMapping("api/post")
@RequiredArgsConstructor
public class PostController {
private final PostRepository repository;
private final GeneratorPost generatorPost;
@GetMapping("generate")
public void generate() {
generatorPost.generate();
}
@GetMapping
public Page<Post> getAll(
@RequestParam("offset") Integer offset,
@RequestParam("limit") Integer limit
@RequestParam(value = "offset", defaultValue = "0") @Min(0) Integer offset,
@RequestParam(value = "limit", defaultValue = "20") Integer 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;
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.Query;
import org.springframework.data.repository.query.Param;
import java.util.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;
import org.h2.tools.Server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.context.annotation.Bean;
import java.sql.SQLException;
@SpringBootApplication
public class SpringPaginationApplication {
@ -11,4 +14,9 @@ public class SpringPaginationApplication {
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:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/test
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:demo
username: sa
password: password
jpa:
hibernate:
ddl-auto: update
ddl-auto: create-drop
show-sql: true
properties:
hibernate:
format_sql: true
format_sql: true
logging:
level:
org:
hibernate:
type: trace