diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000000..1afb82bd42
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000000..017a39f7f5
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000000..f04507a101
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/thriftCompiler.xml b/.idea/thriftCompiler.xml
new file mode 100644
index 0000000000..7bc123c6bc
--- /dev/null
+++ b/.idea/thriftCompiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000..35eb1ddfbb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-11-2/pom.xml b/core-java-modules/core-java-11-2/pom.xml
index f43f8be442..5d7b1b7ddb 100644
--- a/core-java-modules/core-java-11-2/pom.xml
+++ b/core-java-modules/core-java-11-2/pom.xml
@@ -18,7 +18,7 @@
com.google.guava
guava
- ${guava.version}
+ ${version.guava}
org.mock-server
diff --git a/core-java-modules/core-java-11/pom.xml b/core-java-modules/core-java-11/pom.xml
index c7a9259c36..a16fce9454 100644
--- a/core-java-modules/core-java-11/pom.xml
+++ b/core-java-modules/core-java-11/pom.xml
@@ -20,7 +20,7 @@
com.google.guava
guava
- ${guava.version}
+ ${version.guava}
org.openjdk.jmh
diff --git a/core-java-modules/core-java-datetime-conversion/pom.xml b/core-java-modules/core-java-datetime-conversion/pom.xml
index fc16899a9b..8c16d41288 100644
--- a/core-java-modules/core-java-datetime-conversion/pom.xml
+++ b/core-java-modules/core-java-datetime-conversion/pom.xml
@@ -29,7 +29,7 @@
log4j
log4j
- ${log4j.version}
+ ${version.log4j}
diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml
index a9e2448391..e35efd2ecd 100644
--- a/core-java-modules/core-java-io/pom.xml
+++ b/core-java-modules/core-java-io/pom.xml
@@ -71,12 +71,12 @@
log4j
log4j
- ${log4j.version}
+ ${version.log4j}
org.slf4j
log4j-over-slf4j
- ${slf4j.version}
+ ${version.slf4j}
org.projectlombok
diff --git a/core-java-modules/core-java-streams/pom.xml b/core-java-modules/core-java-streams/pom.xml
index 66d50824a9..405da8f8d2 100644
--- a/core-java-modules/core-java-streams/pom.xml
+++ b/core-java-modules/core-java-streams/pom.xml
@@ -35,7 +35,7 @@
log4j
log4j
- ${log4j.version}
+ ${version.log4j}
org.projectlombok
diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml
index 4178a8129b..817e092d33 100644
--- a/core-java-modules/pom.xml
+++ b/core-java-modules/pom.xml
@@ -18,7 +18,7 @@
core-java-8
core-java-8-2
core-java-11
- core-java-11-2
+
core-java-annotations
core-java-collections
core-java-collections-2
diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml
index ba849ccd3f..24f895813e 100644
--- a/parent-boot-2/pom.xml
+++ b/parent-boot-2/pom.xml
@@ -5,7 +5,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
parent-boot-2
- 0.0.1-SNAPSHOT
+ 0.0.2-SNAPSHOT
parent-boot-2
pom
Parent for all Spring Boot 2 modules
@@ -13,7 +13,7 @@
com.ossez
parent-modules
- 0.0.1
+ 0.0.2-SNAPSHOT
diff --git a/persistence-modules/activejdbc/pom.xml b/persistence-modules/activejdbc/pom.xml
index e971c3859f..9a4298c59c 100644
--- a/persistence-modules/activejdbc/pom.xml
+++ b/persistence-modules/activejdbc/pom.xml
@@ -9,9 +9,9 @@
http://maven.apache.org
- com.baeldung
+ com.ossez
persistence-modules
- 1.0.0-SNAPSHOT
+ 0.0.2-SNAPSHOT
diff --git a/persistence-modules/hibernate5/pom.xml b/persistence-modules/hibernate5/pom.xml
index 042f67118a..e2591c51a0 100644
--- a/persistence-modules/hibernate5/pom.xml
+++ b/persistence-modules/hibernate5/pom.xml
@@ -8,9 +8,9 @@
hibernate5
- com.baeldung
+ com.ossez
persistence-modules
- 1.0.0-SNAPSHOT
+ 0.0.2-SNAPSHOT
diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml
index 1cf9977737..c0467cdee2 100644
--- a/persistence-modules/pom.xml
+++ b/persistence-modules/pom.xml
@@ -9,70 +9,82 @@
com.ossez
parent-modules
- 1.0.0
+ 0.0.2-SNAPSHOT
+ ../pom.xml
activejdbc
- apache-cayenne
- core-java-persistence
- deltaspike
- elasticsearch
- flyway
- hbase
- hibernate5
- hibernate-mapping
- hibernate-ogm
- hibernate-annotations
- hibernate-jpa
- hibernate-queries
- hibernate-enterprise
- influxdb
- java-cassandra
- java-cockroachdb
- java-jdbi
- java-jpa
- java-jpa-2
- java-mongodb
- jnosql
- jpa-hibernate-cascade-type
- liquibase
- orientdb
- persistence-libraries
- querydsl
- r2dbc
- redis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- solr
- spring-boot-persistence-2
- spring-boot-mysql
- spring-boot-persistence
- spring-boot-persistence-h2
- spring-boot-persistence-mongodb
- spring-data-cassandra
- spring-data-cassandra-reactive
- spring-data-couchbase-2
- spring-data-dynamodb
- spring-data-eclipselink
- spring-data-elasticsearch
- spring-data-gemfire
- spring-data-geode
- spring-data-jpa
- spring-data-jpa-2
- spring-data-jpa-3
- spring-data-jpa-4
- spring-data-keyvalue
- spring-data-mongodb
- spring-data-neo4j
- spring-data-redis
- spring-data-solr
- spring-hibernate-3
- spring-hibernate-5
- spring-hibernate4
- spring-jpa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spring-data-jpa-repo-2
+
+
+
+
+
+
+
+
+
- spring-persistence-simple
- spring-persistence-simple-2
+
+
diff --git a/persistence-modules/spring-data-jpa-repo-2/README.md b/persistence-modules/spring-data-jpa-repo-2/README.md
new file mode 100644
index 0000000000..6403510e6f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/README.md
@@ -0,0 +1,9 @@
+## Spring Data JPA - Repositories
+
+### Relevant Articles:
+
+- [Introduction to Spring Data JPA](https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa)
+- [Performance Difference Between save() and saveAll() in Spring Data](https://www.baeldung.com/spring-data-save-saveall)
+- [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries)
+- [How to Access EntityManager with Spring Data](https://www.baeldung.com/spring-data-entitymanager)
+- More articles: [[<-- prev]](../spring-data-jpa-repo)
diff --git a/persistence-modules/spring-data-jpa-repo-2/pom.xml b/persistence-modules/spring-data-jpa-repo-2/pom.xml
new file mode 100644
index 0000000000..aac12db474
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+ spring-data-jpa-repo-2
+ spring-data-jpa-repo-2
+
+ 11
+ 11
+
+
+
+ com.ossez
+ parent-boot-2
+ 0.0.2-SNAPSHOT
+ ../../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ javax.persistence
+ javax.persistence-api
+
+
+ org.springframework.data
+ spring-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+
+
+
+ com.google.guava
+ guava
+ ${version.guava}
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryApplication.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryApplication.java
new file mode 100644
index 0000000000..f8f42aa67c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.spring.data.persistence.customrepository;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class CustomRepositoryApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CustomRepositoryApplication.class, args);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/model/User.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/model/User.java
new file mode 100644
index 0000000000..ba217577f3
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/model/User.java
@@ -0,0 +1,55 @@
+package com.baeldung.spring.data.persistence.customrepository.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import java.util.Objects;
+
+@Entity
+public class User {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ private String name;
+ private String email;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ User user = (User) o;
+ return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(email, user.email);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, email);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepository.java
new file mode 100644
index 0000000000..2c79e518b6
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.spring.data.persistence.customrepository.repository;
+
+import com.baeldung.spring.data.persistence.customrepository.model.User;
+
+public interface CustomUserRepository {
+
+ User customFindMethod(Long id);
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepositoryImpl.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepositoryImpl.java
new file mode 100644
index 0000000000..dc006580c1
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepositoryImpl.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.data.persistence.customrepository.repository;
+
+import com.baeldung.spring.data.persistence.customrepository.model.User;
+
+import javax.annotation.PostConstruct;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.Objects;
+
+public class CustomUserRepositoryImpl implements CustomUserRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Override
+ public User customFindMethod(Long id) {
+ return (User) entityManager.createQuery("FROM User u WHERE u.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+ }
+
+ @PostConstruct
+ public void postConstruct() {
+ Objects.requireNonNull(entityManager);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/UserRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/UserRepository.java
new file mode 100644
index 0000000000..d9f60015cc
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/UserRepository.java
@@ -0,0 +1,10 @@
+package com.baeldung.spring.data.persistence.customrepository.repository;
+
+import com.baeldung.spring.data.persistence.customrepository.model.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepository extends JpaRepository, CustomUserRepository {
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/LikeApplication.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/LikeApplication.java
new file mode 100644
index 0000000000..26a5723977
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/LikeApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.data.persistence.like;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class LikeApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(LikeApplication.class, args);
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/model/Movie.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/model/Movie.java
new file mode 100644
index 0000000000..f500b61a8a
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/model/Movie.java
@@ -0,0 +1,58 @@
+package com.baeldung.spring.data.persistence.like.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Movie {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private Long id;
+ private String title;
+ private String director;
+ private String rating;
+ private int duration;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDirector() {
+ return director;
+ }
+
+ public void setDirector(String director) {
+ this.director = director;
+ }
+
+ public String getRating() {
+ return rating;
+ }
+
+ public void setRating(String rating) {
+ this.rating = rating;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public void setDuration(int duration) {
+ this.duration = duration;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/repository/MovieRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/repository/MovieRepository.java
new file mode 100644
index 0000000000..57befb5943
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/like/repository/MovieRepository.java
@@ -0,0 +1,40 @@
+package com.baeldung.spring.data.persistence.like.repository;
+
+import com.baeldung.spring.data.persistence.like.model.Movie;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface MovieRepository extends CrudRepository {
+
+ List findByTitleContaining(String title);
+
+ List findByTitleLike(String title);
+
+ List findByTitleContains(String title);
+
+ List findByTitleIsContaining(String title);
+
+ List findByRatingStartsWith(String rating);
+
+ List findByDirectorEndsWith(String director);
+
+ List findByTitleContainingIgnoreCase(String title);
+
+ List findByRatingNotContaining(String rating);
+
+ List findByDirectorNotLike(String director);
+
+ @Query("SELECT m FROM Movie m WHERE m.title LIKE %:title%")
+ List searchByTitleLike(@Param("title") String title);
+
+ @Query("SELECT m FROM Movie m WHERE m.rating LIKE ?1%")
+ List searchByRatingStartsWith(String rating);
+
+ //Escaping works in SpringBoot >= 2.4.1
+ //@Query("SELECT m FROM Movie m WHERE m.director LIKE %?#{escape([0])} escape ?#{escapeCharacter()}")
+ @Query("SELECT m FROM Movie m WHERE m.director LIKE %:#{[0]}")
+ List searchByDirectorEndsWith(String director);
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/Foo.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/Foo.java
new file mode 100644
index 0000000000..6833c4c556
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/Foo.java
@@ -0,0 +1,72 @@
+package com.baeldung.spring.data.persistence.repository;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+@Entity
+public class Foo implements Serializable {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ public Foo() {
+ super();
+ }
+
+ public Foo(final String name) {
+ super();
+
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Foo other = (Foo) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Foo [name=").append(name).append("]");
+ return builder.toString();
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/FooService.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/FooService.java
new file mode 100644
index 0000000000..cb09a92b82
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/FooService.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.data.persistence.repository;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FooService implements IFooService {
+ @Autowired
+ private IFooDAO dao;
+
+ @Override
+ public Foo create(Foo foo) {
+ return dao.save(foo);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooDAO.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooDAO.java
new file mode 100644
index 0000000000..20a81e7bfa
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooDAO.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.data.persistence.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface IFooDAO extends JpaRepository {
+
+ Foo findByName(String name);
+
+ @Query("SELECT f FROM Foo f WHERE LOWER(f.name) = LOWER(:name)")
+ Foo retrieveByName(@Param("name") String name);
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooService.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooService.java
new file mode 100644
index 0000000000..8ce6a2d1ae
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/IFooService.java
@@ -0,0 +1,5 @@
+package com.baeldung.spring.data.persistence.repository;
+
+public interface IFooService {
+ Foo create(Foo foo);
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/PersistenceConfig.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/PersistenceConfig.java
new file mode 100644
index 0000000000..f73ea94658
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/repository/PersistenceConfig.java
@@ -0,0 +1,81 @@
+package com.baeldung.spring.data.persistence.repository;
+
+import com.google.common.base.Preconditions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.sql.DataSource;
+import java.util.Properties;
+
+@Configuration
+@PropertySource("classpath:persistence.properties")
+@ComponentScan("com.baeldung.spring.data.persistence.repository")
+//@ImportResource("classpath*:*springDataConfig.xml")
+@EnableTransactionManagement
+@EnableJpaRepositories(basePackages = "com.baeldung.spring.data.persistence.repository")
+public class PersistenceConfig {
+
+ @Autowired
+ private Environment env;
+
+ public PersistenceConfig() {
+ super();
+ }
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(dataSource());
+ em.setPackagesToScan("com.baeldung.spring.data.persistence.repository");
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ em.setJpaProperties(additionalProperties());
+
+ return em;
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
+ dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
+ dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
+ dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
+
+ return dataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
+
+ return transactionManager;
+ }
+
+ @Bean
+ public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+ return new PersistenceExceptionTranslationPostProcessor();
+ }
+
+ final Properties additionalProperties() {
+ final Properties hibernateProperties = new Properties();
+ hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
+
+ return hibernateProperties;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/Book.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/Book.java
new file mode 100644
index 0000000000..b6abdd2ed5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/Book.java
@@ -0,0 +1,25 @@
+package com.baeldung.spring.data.persistence.saveperformance;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Book {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ private String title;
+ private String author;
+
+ public Book(final String title, final String author) {
+ this.title = title;
+ this.author = author;
+ }
+
+ public Book() {
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookApplication.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookApplication.java
new file mode 100644
index 0000000000..46cb8d3453
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookApplication.java
@@ -0,0 +1,52 @@
+package com.baeldung.spring.data.persistence.saveperformance;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SpringBootApplication
+public class BookApplication {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(BookApplication.class);
+
+ @Autowired
+ private BookRepository bookRepository;
+
+ public static void main(String[] args) {
+ SpringApplication.run(BookApplication.class, args);
+ }
+
+ @EventListener(ApplicationReadyEvent.class)
+ public void executePerformanceBenchmark() {
+
+ int bookCount = 10000;
+
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < bookCount; i++) {
+ bookRepository.save(new Book("Book " + i, "Author " + i));
+ }
+ long end = System.currentTimeMillis();
+ bookRepository.deleteAll();
+
+ LOGGER.debug("It took {}ms to execute save() for {} books.", (end - start), bookCount);
+
+ List bookList = new ArrayList<>();
+ for (int i = 0; i < bookCount; i++) {
+ bookList.add(new Book("Book " + i, "Author " + i));
+ }
+
+ start = System.currentTimeMillis();
+ bookRepository.saveAll(bookList);
+ end = System.currentTimeMillis();
+
+ LOGGER.debug("It took {}ms to execute saveAll() with {}} books.", (end - start), bookCount);
+
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookRepository.java
new file mode 100644
index 0000000000..9db4a18796
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/BookRepository.java
@@ -0,0 +1,7 @@
+package com.baeldung.spring.data.persistence.saveperformance;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface BookRepository extends JpaRepository {
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties
new file mode 100644
index 0000000000..cb1eab9443
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
+spring.datasource.username=sa
+spring.datasource.password=sa
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/resources/persistence.properties b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/persistence.properties
new file mode 100644
index 0000000000..05cb7a13b9
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/persistence.properties
@@ -0,0 +1,9 @@
+# jdbc.X
+jdbc.driverClassName=org.h2.Driver
+jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
+jdbc.user=sa
+jdbc.pass=sa
+
+# hibernate.X
+hibernate.hbm2ddl.auto=create-drop
+hibernate.dialect=org.hibernate.dialect.H2Dialect
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/resources/springDataConfig.xml b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/springDataConfig.xml
new file mode 100644
index 0000000000..b2616d9eae
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/springDataConfig.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryUnitTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryUnitTest.java
new file mode 100644
index 0000000000..ed54225a14
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/customrepository/CustomRepositoryUnitTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.data.persistence.customrepository;
+
+import com.baeldung.spring.data.persistence.customrepository.model.User;
+import com.baeldung.spring.data.persistence.customrepository.repository.UserRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SpringBootTest(classes = CustomRepositoryApplication.class)
+class CustomRepositoryUnitTest {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Test
+ void givenCustomRepository_whenInvokeCustomFindMethod_thenEntityIsFound() {
+ User user = new User();
+ user.setEmail("foo@gmail.com");
+ user.setName("userName");
+
+ User persistedUser = userRepository.save(user);
+
+ assertEquals(persistedUser, userRepository.customFindMethod(user.getId()));
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/like/MovieRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/like/MovieRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..291926c127
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/like/MovieRepositoryIntegrationTest.java
@@ -0,0 +1,91 @@
+package com.baeldung.spring.data.persistence.like;
+
+import com.baeldung.spring.data.persistence.like.model.Movie;
+import com.baeldung.spring.data.persistence.like.repository.MovieRepository;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
+
+@RunWith(SpringRunner.class)
+@Sql(scripts = { "/test-movie-data.sql" })
+@SpringBootTest(classes = LikeApplication.class)
+@Sql(scripts = "/test-movie-cleanup.sql", executionPhase = AFTER_TEST_METHOD)
+public class MovieRepositoryIntegrationTest {
+ @Autowired
+ private MovieRepository movieRepository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void givenPartialTitle_WhenFindByTitleContaining_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByTitleContaining("in");
+ assertEquals(3, results.size());
+
+ results = movieRepository.findByTitleLike("%in%");
+ assertEquals(3, results.size());
+
+ results = movieRepository.findByTitleIsContaining("in");
+ assertEquals(3, results.size());
+
+ results = movieRepository.findByTitleContains("in");
+ assertEquals(3, results.size());
+ }
+
+ @Test
+ public void givenStartOfRating_WhenFindByRatingStartsWith_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByRatingStartsWith("PG");
+ assertEquals(6, results.size());
+ }
+
+ @Test
+ public void givenLastName_WhenFindByDirectorEndsWith_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByDirectorEndsWith("Burton");
+ assertEquals(1, results.size());
+ }
+
+ @Test
+ public void givenPartialTitle_WhenFindByTitleContainingIgnoreCase_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByTitleContainingIgnoreCase("the");
+ assertEquals(2, results.size());
+ }
+
+ @Test
+ public void givenPartialTitle_WhenSearchByTitleLike_ThenMoviesShouldReturn() {
+ List results = movieRepository.searchByTitleLike("in");
+ assertEquals(3, results.size());
+ }
+
+ @Test
+ public void givenStartOfRating_SearchFindByRatingStartsWith_ThenMoviesShouldReturn() {
+ List results = movieRepository.searchByRatingStartsWith("PG");
+ assertEquals(6, results.size());
+ }
+
+ @Test
+ public void givenLastName_WhenSearchByDirectorEndsWith_ThenMoviesShouldReturn() {
+ List results = movieRepository.searchByDirectorEndsWith("Burton");
+ assertEquals(1, results.size());
+ }
+
+ @Test
+ public void givenPartialRating_findByRatingNotContaining_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByRatingNotContaining("PG");
+ assertEquals(1, results.size());
+ }
+
+ @Test
+ public void givenPartialDirector_WhenFindByDirectorNotLike_ThenMoviesShouldReturn() {
+ List results = movieRepository.findByDirectorNotLike("An%");
+ assertEquals(5, results.size());
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/repository/FooServiceIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/repository/FooServiceIntegrationTest.java
new file mode 100644
index 0000000000..21990afb5e
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/repository/FooServiceIntegrationTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.data.persistence.repository;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = PersistenceConfig.class)
+public class FooServiceIntegrationTest {
+
+ @Autowired
+ private IFooService service;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test(expected = DataIntegrityViolationException.class)
+ public final void whenInvalidEntityIsCreated_thenDataException() {
+ service.create(new Foo());
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/resources/logback-test.xml b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..8d4771e308
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/logback-test.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-cleanup.sql b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-cleanup.sql
new file mode 100644
index 0000000000..90aa15307c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-cleanup.sql
@@ -0,0 +1 @@
+DELETE FROM Movie;
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-data.sql b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-data.sql
new file mode 100644
index 0000000000..37f8e4fe64
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/test-movie-data.sql
@@ -0,0 +1,7 @@
+INSERT INTO movie(id, title, director, rating, duration) VALUES(1, 'Godzilla: King of the Monsters', ' Michael Dougherty', 'PG-13', 132);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(2, 'Avengers: Endgame', 'Anthony Russo', 'PG-13', 181);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(3, 'Captain Marvel', 'Anna Boden', 'PG-13', 123);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(4, 'Dumbo', 'Tim Burton', 'PG', 112);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(5, 'Booksmart', 'Olivia Wilde', 'R', 102);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(6, 'Aladdin', 'Guy Ritchie', 'PG', 128);
+INSERT INTO movie(id, title, director, rating, duration) VALUES(7, 'The Sun Is Also a Star', 'Ry Russo-Young', 'PG-13', 100);
diff --git a/pom.xml b/pom.xml
index 118265cceb..569fc9b32c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,6 +43,7 @@
+ persistence-modules
testing-modules
toolkits
@@ -55,9 +56,9 @@
UTF-8
- 1.7.30
- 1.2.17
- 2.2
+ 1.7.36
+ 1.2.17
+ 2.18.0
2.8.0
@@ -71,7 +72,7 @@
3.0.0
- 31.1-jre
+ 31.1-jre
4.3.5.Final