diff --git a/pom.xml b/pom.xml
index dbbc679..c52369b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,9 +27,8 @@
- org.postgresql
- postgresql
- runtime
+ com.h2database
+ h2
org.projectlombok
@@ -40,12 +39,12 @@
io.swagger.core.v3
swagger-annotations
- 2.2.4
+ 2.2.6
org.springdoc
springdoc-openapi-ui
- 1.6.11
+ 1.6.12
diff --git a/request/requests.http b/request/requests.http
new file mode 100644
index 0000000..1107670
--- /dev/null
+++ b/request/requests.http
@@ -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
\ No newline at end of file
diff --git a/sql_examples.sql b/sql_examples.sql
new file mode 100644
index 0000000..2a713e1
--- /dev/null
+++ b/sql_examples.sql
@@ -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
\ No newline at end of file
diff --git a/src/main/java/dev/struchkov/example/GeneratorPost.java b/src/main/java/dev/struchkov/example/GeneratorPost.java
index eb7ef6a..1901745 100644
--- a/src/main/java/dev/struchkov/example/GeneratorPost.java
+++ b/src/main/java/dev/struchkov/example/GeneratorPost.java
@@ -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 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);
}
}
diff --git a/src/main/java/dev/struchkov/example/PostController.java b/src/main/java/dev/struchkov/example/PostController.java
index 5d856d1..dc579b2 100644
--- a/src/main/java/dev/struchkov/example/PostController.java
+++ b/src/main/java/dev/struchkov/example/PostController.java
@@ -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 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 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 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 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 getAllSqlNative(
+ @RequestParam("title") String title,
+ @RequestParam("offset") Integer offset,
+ @RequestParam("limit") Integer limit
+ ) {
+ return repository.findAllByTitleNative(title, PageRequest.of(offset, limit));
+ }
+
}
diff --git a/src/main/java/dev/struchkov/example/PostRepository.java b/src/main/java/dev/struchkov/example/PostRepository.java
index 61e35a1..64bff4a 100644
--- a/src/main/java/dev/struchkov/example/PostRepository.java
+++ b/src/main/java/dev/struchkov/example/PostRepository.java
@@ -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 {
+ Page findAllByTitleLikeIgnoreCase(String titleLike, Pageable pageable);
+
+ @Query("SELECT p FROM Post p WHERE p.title like %:title%")
+ Page 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 findAllByTitleNative(String title, Pageable pageable);
+
}
diff --git a/src/main/java/dev/struchkov/example/PostSort.java b/src/main/java/dev/struchkov/example/PostSort.java
new file mode 100644
index 0000000..796150f
--- /dev/null
+++ b/src/main/java/dev/struchkov/example/PostSort.java
@@ -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;
+
+}
diff --git a/src/main/java/dev/struchkov/example/SpringPaginationApplication.java b/src/main/java/dev/struchkov/example/SpringPaginationApplication.java
index be90641..b019511 100644
--- a/src/main/java/dev/struchkov/example/SpringPaginationApplication.java
+++ b/src/main/java/dev/struchkov/example/SpringPaginationApplication.java
@@ -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");
+ }
+
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 0d4a7c7..c1936d4 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -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
\ No newline at end of file
+ format_sql: true
+logging:
+ level:
+ org:
+ hibernate:
+ type: trace
\ No newline at end of file