Persistence With Spring PDF
Persistence With Spring PDF
Persistence With Spring PDF
Spring
Table of Contents
2.2. Configuration 2
7. Conclusion 11
2. Spring Integration 14
3. Maven Dependencies 15
Table of Contents
4. Configuration 16
5. Usage 20
6. Supported Databases 21
7. Conclusion 22
3. The DAO 26
4. Conclusion 28
Table of Contents
4. Conclusion 37
5. Potential Pitfalls 43
6. Conclusion 45
4. Transaction Configuration 52
9. Conclusion 57
2. Select Query 60
2.1. JPQL 60
2.2. Native 60
3.2. JPQL 62
3.3. Native 63
4. Pagination 64
4.1. JPQL 64
4.2. Native 64
5.1. JPQL 66
5.2. Native 66
6. Named Parameters 67
6.1. JPQL 67
6.2. Native 68
7. Collection Parameter 69
8.1. JPQL 70
8.2. Native 70
8.3. Inserts 71
9. Dynamic Query 72
10. Conclusion 75
Table of Contents
8: Spring JDBC
1. Overview 77
2. Configuration 78
4. Exception Translation 83
5.1. SimpleJdbcInsert 84
6. Batch operations 86
7.2. Configuration 88
8. Conclusion 89
1: A Guide to JPA with Spring
9
1. Overview
This chapter shows how to set up Spring with JPA, using Hibernate as a
persistence provider.
For a step by step introduction about setting up the Spring context using
Java based configuration and the basic Maven pom for the project, see this
article.
We’ll start by setting up JPA in a Spring Boot project, then we’ll look into the
full configuration we need if we have a standard Spring project.
1
2. JPA in Spring Boot
1. <dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter</artifactId>
4. <version>2.1.4.RELEASE</version>
5. </dependency>
6. <dependency>
7. <groupId>org.springframework.boot</groupId>
8. <artifactId>spring-boot-starter-data-jpa</artifactId>
9. <version>2.1.4.RELEASE</version>
10. </dependency>
2.2. Configuration
2
1. <dependency>
2. <groupId>com.h2database</groupId>
3. <artifactId>h2</artifactId>
4. <version>1.4.197</version>
5. </dependency>
This way, we don’t need to define the dataSource bean, but we can do so if
we want to customize it.
The Java configuration looks the same as it does in a standard Spring project:
1. @Bean
2. public DataSource dataSource() {
3. DriverManagerDataSource dataSource = new DriverManagerDataSource();
4.
5. dataSource.setDriverClassName(“com.mysql.cj.jdbc.Driver”);
6. dataSource.setUsername(“mysqluser”);
7. dataSource.setPassword(“mysqlpass”);
8. dataSource.setUrl(
9. “jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true”);
10.
11. return dataSource;
12. }
To configure the data source using a properties file, we have to set properties
prefixed with spring.datasource:
1. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
2. spring.datasource.username=mysqluser
3. spring.datasource.password=mysqlpass
4. spring.datasource.url=
5. jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true
3
Spring Boot will automatically configure a data source based on these
properties.
Also in Spring Boot 1, the default connection pool was Tomcat, but with
Spring Boot 2 it has been changed to HikariCP.
You can find more examples of configuring JPA in Spring Boot in the GitHub
project.
As we can see, the basic JPA configuration is fairly simple if we’re using
Spring Boot.
4
3. The JPA Spring Configuration with Java
This is the main part of the configuration and we can do it via a Spring factory
bean. This can be either the simpler LocalEntityManagerFactoryBean or the
more flexible LocalContainerEntityManagerFactoryBean.
1. @Configuration
2. @EnableTransactionManagement
3. public class PersistenceJPAConfig{
4.
5. @Bean
6. public LocalContainerEntityManagerFactoryBean entityManagerFactory()
7. {
8. LocalContainerEntityManagerFactoryBean em
9. = new LocalContainerEntityManagerFactoryBean();
10. em.setDataSource(dataSource());
11. em.setPackagesToScan(new String[] { “com.baeldung.persistence.
12. model” });
13.
14. JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
15. em.setJpaVendorAdapter(vendorAdapter);
16. em.setJpaProperties(additionalProperties());
17.
18. return em;
19. }
20.
21. // ...
22.
23. }
5
We also need to explicitly define the DataSource bean we’ve used above:
1. @Bean
2. public DataSource dataSource(){
3. DriverManagerDataSource dataSource = new DriverManagerDataSource();
4. dataSource.setDriverClassName(“com.mysql.cj.jdbc.Driver”);
5. dataSource.setUrl(“jdbc:mysql://localhost:3306/spring_jpa”);
6. dataSource.setUsername( “tutorialuser” );
7. dataSource.setPassword( “tutorialmy5ql” );
8. return dataSource;
9. }
The final part of the configuration are the additional Hibernate properties
and the TransactionManager and exceptionTranslation beans:
1. @Bean
2. public PlatformTransactionManager
3. transactionManager(EntityManagerFactory emf) {
4. JpaTransactionManager transactionManager = new
5. JpaTransactionManager();
6. transactionManager.setEntityManagerFactory(emf);
7.
8. return transactionManager;
9. }
10.
11. @Bean
12. public PersistenceExceptionTranslationPostProcessor
13. exceptionTranslation(){
14. return new PersistenceExceptionTranslationPostProcessor();
15. }
16.
17. Properties additionalProperties() {
18. Properties properties = new Properties();
19. properties.setProperty(“hibernate.hbm2ddl.auto”, “create-drop”);
20. properties.setProperty(“hibernate.dialect”, “org.hibernate.dialect.
21. MySQL5Dialect”);
22.
23. return properties;
24. }
6
4. The JPA Spring Configuration with XML
1. <bean id=”myEmf”
2. class=”org.springframework.orm.jpa.
3. LocalContainerEntityManagerFactoryBean”>
4. <property name=”dataSource” ref=”dataSource” />
5. <property name=”packagesToScan” value=”com.baeldung.persistence.
6. model” />
7. <property name=”jpaVendorAdapter”>
8. <bean class=”org.springframework.orm.jpa.vendor.
9. HibernateJpaVendorAdapter” />
10. </property>
11. <property name=”jpaProperties”>
12. <props>
13. <prop key=”hibernate.hbm2ddl.auto”>create-drop</prop>
14. <prop key=”hibernate.dialect”>org.hibernate.dialect.
15. MySQL5Dialect</prop>
16. </props>
17. </property>
18. </bean>
19.
20. <bean id=”dataSource”
21. class=”org.springframework.jdbc.datasource.DriverManagerDataSource”>
22. <property name=”driverClassName” value=”com.mysql.cj.jdbc.Driver” />
23. <property name=”url” value=”jdbc:mysql://localhost:3306/spring_jpa”
24. />
25. <property name=”username” value=”tutorialuser” />
26. <property name=”password” value=”tutorialmy5ql” />
27. </bean>
28.
29. <bean id=”transactionManager” class=”org.springframework.orm.jpa.
30. JpaTransactionManager”>
31. <property name=”entityManagerFactory” ref=”myEmf” />
32. </bean>
33. <tx:annotation-driven />
34.
35. <bean id=”persistenceExceptionTranslationPostProcessor” class=
36. “org.springframework.dao.annotation.
37. PersistenceExceptionTranslationPostProcessor” />
7
There is a relatively small difference between the XML and the new Java-
based configuration. Namely, in XML, a reference to another bean can point
to either the bean or a bean factory for that bean.
In Java, however, since the types are different, the compiler doesn’t allow it,
and so the EntityManagerFactory is first retrieved from its bean factory and
then passed to the transaction manager:
txManager.setEntityManagerFactory(this.entityManagerFactoryBean().
getObject());
8
5. Going Full XML-less
This file was the last piece of XML we need to remove. We can now set up
JPA fully with no XML.
factoryBean.setJpaProperties(this.additionalProperties());
9
6. The Maven Configuration
1. <dependency>
2. <groupId>org.hibernate</groupId>
3. <artifactId>hibernate-entitymanager</artifactId>
4. <version>5.4.2.Final</version>
5. <scope>runtime</scope>
6. </dependency>
7.
8. <dependency>
9. <groupId>mysql</groupId>
10. <artifactId>mysql-connector-java</artifactId>
11. <version>6.0.6</version>
12. <scope>runtime</scope>
13. </dependency>
10
7. Conclusion
11
2: Bootstrapping Hibernate 5 with Spring
12
1. Overview
In this chapter, we’ll discuss how to bootstrap Hibernate 5 with Spring, using
both Java and XML configuration.
13
2. Spring Integration
Also, before we jump in, if you’re working with older versions of Hibernate,
you can have a look at the articles about Hibernate 3 as well as Hibernate 4
with Spring.
14
3. Maven Dependencies
1. <dependency>
2. <groupId>org.hibernate</groupId>
3. <artifactId>hibernate-core</artifactId>
4. <version>5.4.2.Final</version>
5. </dependency>
1. <dependency>
2. <groupId>org.springframework</groupId>
3. <artifactId>spring-orm</artifactId>
4. <version>5.1.6.RELEASE</version>
5. </dependency>
1. <dependency>
2. <groupId>com.h2database</groupId>
3. <artifactId>h2</artifactId>
4. <version>1.4.197</version>
5. </dependency>
Finally, we are going to use Tomcat JDBC Connection Pooling, which fits
better for production purposes than the DriverManagerDataSource provided
by Spring:
1. <dependency>
2. <groupId>org.apache.tomcat</groupId>
3. <artifactId>tomcat-dbcp</artifactId>
4. <version>9.0.1</version>
5. </dependency>
15
4. Configuration
For using Hibernate 5 with Spring, little has changed since Hibernate 4:
we have to use LocalSessionFactoryBean from the package org.
springframework.orm.hibernate5 instead of
org.springframework.orm.hibernate4.
16
1. @Configuration
2. @EnableTransactionManagement
3. public class HibernateConf {
4.
5. @Bean
6. public LocalSessionFactoryBean sessionFactory() {
7. LocalSessionFactoryBean sessionFactory = new
8. LocalSessionFactoryBean();
9. sessionFactory.setDataSource(dataSource());
10. sessionFactory.setPackagesToScan(
11. {“com.baeldung.hibernate.bootstrap.model” });
12. sessionFactory.setHibernateProperties(hibernateProperties());
13.
14. return sessionFactory;
15. }
16.
17. @Bean
18. public DataSource dataSource() {
19. BasicDataSource dataSource = new BasicDataSource();
20. dataSource.setDriverClassName(“org.h2.Driver”);
21. dataSource.setUrl(“jdbc:h2:mem:db;DB_CLOSE_DELAY=-1”);
22. dataSource.setUsername(“sa”);
23. dataSource.setPassword(“sa”);
24.
25. return dataSource;
26. }
27.
28. @Bean
29. public PlatformTransactionManager hibernateTransactionManager() {
30. HibernateTransactionManager transactionManager
31. = new HibernateTransactionManager();
32. transactionManager.setSessionFactory(sessionFactory().
33. getObject());
34. return transactionManager;
35. }
36.
37. private final Properties hibernateProperties() {
38. Properties hibernateProperties = new Properties();
39. hibernateProperties.setProperty(
40. “hibernate.hbm2ddl.auto”, “create-drop”);
41. hibernateProperties.setProperty(
42. “hibernate.dialect”, “org.hibernate.dialect.H2Dialect”);
43.
44. return hibernateProperties;
45. }
46. }
17
4.2. Using XML Configuration
18
As we can easily see, we’re defining exactly the same beans and parameters
as in the Java-based configuration earlier.
To bootstrap the XML into the Spring context, we can use a simple Java
configuration file if the application is configured with Java configuration:
1. @Configuration
2. @EnableTransactionManagement
3. @ImportResource({“classpath:hibernate5Configuration.xml”})
4. public class HibernateXMLConf {
5. //
6. }
Alternatively, we can simply provide the XML file to the Spring Context, if the
overall configuration is purely XML.
19
5. Usage
At this point, Hibernate 5 is fully configured with Spring, and we can inject
the raw Hibernate SessionFactory directly whenever we need to:
20
6. Supported Databases
That being said, it’s easy to see if a particular database type might be
supported, we can have a look at the list of supported dialects.
21
7. Conclusion
As always, the full source code of the examples is available over on GitHub
22
3: The DAO with Spring and Hibernate
23
1. Overview
This chapter will show how to implement the DAO with Spring and Hibernate.
For the core Hibernate configuration, check out the previous chapter.
24
2. No More Spring Templates
As a consequence, it’s now best practice to use the Hibernate API directly
instead of the HibernateTemplate. This will effectively decouple the DAO
layer implementation from Spring entirely.
Without the template, this mechanism is still enabled and active for all
the DAOs annotated with the @Repository annotation. Under the hood, this
uses a Spring bean postprocessor that will advise all @Repository beans
with all the PersistenceExceptionTranslator found in the Spring context.
One thing to remember is that exception translation uses proxies. For Spring
to be able to create proxies around the DAO classes, these must not be
declared as final.
NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in
plain Hibernate style. Hence, for newly started projects, consider adopting the standard
Hibernate3 style of coding data access objects instead, based on {@link org.hibernate.
SessionFactory#getCurrentSession()}.
25
3. The DAO
We’ll start with the base DAO – an abstract, parametrized DAO which
supports the common generic operations and that we can extend for each
entity:
26
A few aspects are interesting here – as discussed, the abstract DAO doesn’t
extend any Spring template (such as HibernateTemplate). Instead, the
Hibernate SessionFactory is injected directly in the DAO, and will have the
role of the main Hibernate API, through the contextual Session it exposes:
this.sessionFactory.getCurrentSession();
Also, note that the constructor receives the Class of the entity as a parameter
to be used in the generic operations.
Now, let’s look at an example implementation of this DAO, for a Foo entity:
1. @Repository
2. public class FooDAO extends AbstractHibernateDAO< Foo > implements
3. IFooDAO{
4.
5. public FooDAO(){
6. setClazz(Foo.class );
7. }
8. }
27
4. Conclusion
The reasons to stop relying on templates for the DAO layer was discussed,
as well as possible pitfalls of configuring Spring to manage transactions
and the Hibernate Session. The final result is a lightweight, clean DAO
implementation, with almost no compile-time reliance on Spring.
The implementation of this simple project can be found in the github project.
28
4: Simplify the DAO with Spring and
Java Generics
29
1. Overview
This chapter will focus on simplifying the DAO layer by using a single,
generified Data Access Object for all entities in the system, which will result
in elegant data access, with no unnecessary clutter or verbosity.
We’ll build on the Abstract DAO class we saw in our previous chapter on
Spring and Hibernate, and add generics support.
30
2. The Hibernate and JPA DAOs
Most production codebases have some kind of DAO layer. Usually, the
implementation ranges from multiple classes with no abstract base class
to some kind of generified class. However, one thing is consistent – there
is always more than one. Most likely, there is a one to one relation between
the DAOs and the entities in the system.
We’ll show two implementations of this concept next, one for a Hibernate
centric persistence layer and the other focusing on JPA.
31
2.1. The Abstract Hibernate DAO
This is an abstract class with several data access methods, that uses the
SessionFactory for manipulating entities.
32
2.2. The Generic Hibernate DAO
Now that we have the abstract DAO class, we can extend it just once. The
generic DAO implementation will become the only implementation we need:
1. @Repository
2. @Scope(BeanDefinition.SCOPE_PROTOTYPE)
3. public class GenericHibernateDao<T extends Serializable>
4. extends AbstractHibernateDao<T> implements IGenericDao<T>{
5. //
6. }
The reason this scope is so important is due to the way Spring initializes
beans in the container. Leaving the generic DAO without a scope would mean
using the default singleton scope, which would lead to a single instance of
the DAO living in the container. That would obviously be majorly restrictive
for any kind of more complex scenario.
The IGenericDao is simply an interface for all the DAO methods so that we
can inject the implementation we need:
33
2.3. The Abstract JPA DAO
34
2.4. The Generic JPA DAO
1. @Repository
2. @Scope( BeanDefinition.SCOPE_PROTOTYPE )
3. public class GenericJpaDao< T extends Serializable >
4. extends AbstractJpaDao< T > implements IGenericDao< T >{
5. //
6. }
35
3. Injecting this DAO
We now have a single DAO interface we can inject. We also need to specify
the Class
1. @Service
2. class FooService implements IFooService{
3.
4. IGenericDao<Foo> dao;
5.
6. @Autowired
7. public void setDao(IGenericDao<Foo> daoToSet) {
8. dao = daoToSet;
9. dao.setClazz(Foo.class);
10. }
11.
12. // ...
13. }
Spring autowires the new DAO instance using setter injection so that the
implementation can be customized with the Class object. After this point,
the DAO is fully parametrized and ready to be used by the service.
There are of course other ways that the class can be specified for the DAO –
via reflection, or even in XML. My preference is towards this simpler solution
because of the improved readability and transparency compared to using
reflection.
36
4. Conclusion
For a step by step introduction about setting up the Spring context using
Java based configuration and the basic Maven pom for the project, see this
article.
Finally, the code for this chapter can be found in the GitHub project.
37
5: Transactions with Spring and JPA
38
1. Overview
This chapter will discuss the right way to configure Spring Transactions,
how to use the @Transactional annotation and common pitfalls.
39
2. Configure Transactions without XML
1. @Configuration
2. @EnableTransactionManagement
3. public class PersistenceJPAConfig{
4.
5. @Bean
6. public LocalContainerEntityManagerFactoryBean
7. entityManagerFactoryBean(){
8. //...
9. }
10.
11. @Bean
12. public PlatformTransactionManager transactionManager(){
13. JpaTransactionManager transactionManager
14. = new JpaTransactionManager();
15. transactionManager.setEntityManagerFactory(
16. entityManagerFactoryBean().getObject() );
17. return transactionManager;
18. }
19. }
40
3. Configure Transactions with XML
Before 3.1 or if Java is not an option, here is the XML configuration, using
annotation-driven and the namespace support:
41
4. The @Transactional Annotation
1. @Service
2. @Transactional
3. public class FooService {
4. //...
5. }
42
5. Potential Pitfalls
At a high level, Spring creates proxies for all the classes annotated with
@Transactional – either on the class or on any of the methods. The proxy
allows the framework to inject transactional logic before and after the
running method – mainly for starting and committing the transaction.
1. @Transactional(isolation = Isolation.SERIALIZABLE)
Note that this has actually been introduced in Spring 4.1; if we run the above
example before Spring 4.1, it will result in:
“org.springframework.transaction.InvalidIsolationLevelException: Standard
JPA does not support custom isolation levels – use a special JpaDialect for
your JPA implementation”
43
5.3. Read-Only Transactions
“This just serves as a hint for the actual transaction subsystem; it will not
necessarily cause failure of write access attempts. A transaction manager
which cannot interpret the read-only hint will not throw an exception when
asked for a read-only transaction.”
The fact is that we can’t be sure that an insert or update will not occur
when the readOnly flag is set. This behavior is vendor dependent, whereas
JPA is vendor agnostic.
It’s also important to understand that the readOnly flag is only relevant
inside a transaction. If an operation occurs outside of a transactional context,
the flag is simply ignored. A simple example of that would call a method
annotated with:
44
6. Conclusion
45
6: Introduction to Spring Data JPA
46
1. Overview
This chapter will focus on introducing Spring Data JPA into a Spring project
and fully configuring the persistence layer.
47
2. The Spring Data generated DAO
Spring Data takes this simplification one step forward and makes it possible
to remove the DAO implementations entirely. The interface of the DAO is
now the only artifact that we need to explicitly define.
In order to start leveraging the Spring Data programming model with JPA,
a DAO interface needs to extend the JPA specific Repository interface
– JpaRepository. This will enable Spring Data to find this interface and
automatically create an implementation for it.
By extending the interface we get the most relevant CRUD methods for
standard data access available in a standard DAO.
48
3. Custom Access Method and Queries
To define more specific access methods, Spring JPA supports quite a few
options:
The third option – the Specifications and Querydsl support – is similar to JPA
Criteria but using a more flexible and convenient API. This makes the whole
operation much more readable and reusable. The advantages of this API
will become more pronounced when dealing with a large number of fixed
queries, as we could potentially express these more concisely through a
smaller number of reusable blocks.
This last option has the disadvantage that it either involves XML or burdening
the domain class with the queries.
49
3.1. Automatic Custom Queries
Let’s look at an example: if the entity has a name field (and the Java Bean
standard getName and setName methods), we’ll define the findByName
method in the DAO interface; this will automatically generate the correct
query:
In case that the parser cannot match the property with the domain object
field, we’ll see the following exception:
50
3.2. Manual Custom Queries
Let’s now look at a custom query that we’ll define via the @Query annotation:
For even more fine-grained control over the creation of queries, such as
using named parameters or modifying existing queries, the reference is a
good place to start.
51
4. Transaction Configuration
The question is now – since we’re not using the default Spring ORM templates
(JpaTemplate, HibernateTemplate) – are we losing exception translation by
using Spring Data JPA? Are we not going to get our JPA exceptions translated
to Spring’s DataAccessException hierarchy?
1. @Test(expected = DataIntegrityViolationException.class)
2. public void givenFooHasNoName_whenInvalidEntityIsCreated_
3. thenDataException() {
4. service.create(new Foo());
5. }
52
5. Spring Data Configuration
1. @EnableJpaRepositories(basePackages = “com.baeldung.jpa.dao”)
2. public class PersistenceConfig { ... }
53
6. The Spring Java or XML Configuration
1. @Configuration
2. @EnableTransactionManagement
3. @ImportResource( “classpath*:*springDataConfig.xml” )
4. public class PersistenceJPAConfig{
5. ...
6. }
54
7. The Maven Dependency
1. <dependency>
2. <groupId>org.springframework.data</groupId>
3. <artifactId>spring-data-jpa</artifactId>
4. <version>2.1.6.RELEASE</version>
5. </dependency>
55
8. Using Spring Boot
We can also use the Spring Boot Starter Data JPA dependency that will
automatically configure the DataSource for us.
We also need to make sure that the database we want to use is present in
the classpath. In our example, we’ve added the H2 in-memory database:
1. <dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter-data-jpa</artifactId>
4. <version>2.1.3.RELEASE</version>
5. </dependency>
6. <dependency>
7. <groupId>com.h2database</groupId>
8. <artifactId>h2</artifactId>
9. <version>1.4.197</version>
10. </dependency>
That’s it, just by doing these dependencies, our application is up and running
and we can use it for other database operations.
1. spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
2. spring.datasource.username=sa
3. spring.datasource.password=sa
56
9. Conclusion
57
7: Spring Data JPA @Query
58
1. Overview
Spring Data provides many ways to define a query that we can execute. One
of these is the @Query annotation.
Also, we’ll show how to build a dynamic query when the @Query annotation
is not enough.
59
2. Select Query
The @Query annotation takes precedence over named queries, which are
annotated with @NamedQuery or defined in an orm.xml file.
It’s a good approach to place a query definition just above the method inside
the repository rather than inside our domain model as named queries. The
repository is responsible for persistence, so it’s a better place to store these
definitions.
2.1. JPQL
Let’s look at a simple repository method that returns active User entities
from the database:
2.2. Native
We can use also native SQL to define our query. All we have to do is to set
the value of the nativeQuery attribute to true and define the native SQL query
in the value attribute of the annotation
1. @Query(
2. value = “SELECT * FROM USERS u WHERE u.status = 1”,
3. nativeQuery = true)
4. Collection<User> findAllActiveUsersNative();
60
3. Define Order in a Query
For the methods we get out-of-the-box like findAll(Sort) or the ones that are
generated by parsing method signatures, we can only use object properties
to define our sort:
1. userRepository.findAll(new Sort(“LENGTH(name)”));
org.springframework.data.mapping
PropertyReferenceException: No Property LENGTH(name)
found for type User!
61
3.2. JPQL
When we use JPQL for a query definition, then Spring Data can handle
sorting without any problem — all we have to do is to add a method
parameter of type Sort:
We can call this method and pass a Sort parameter, which will order the
result by the name property of the Userobject:
1. userRepository.findAllUsers(new Sort(“name”));
And because we used @Query annotation, we can use the same method to
get the sorted list of Users by the length of their names:
1. userRepository.findAllUsers(JpaSort.unsafe(“LENGTH(name)”));
1. new Sort(“LENGTH(name)”);
then we’ll receive exactly the same exception as we saw above for the
findAll() method.
When Spring Data discovers the unsafe Sort order for a method that uses
the @Query annotation, then it just appends the sort clause to the query
— it skips checking whether the property to sort by belongs to the domain
model.
62
3.3. Native
When the @Query annotation uses native SQL, then it’s not possible to
define a Sort.
org.springframework.data.jpa.repository.query.
InvalidJpaQueryMethodException: Cannot use native
queries with dynamic sorting and/or pagination
As the exception says, the sort isn’t supported for native queries. The error
message gives us a hint that pagination will cause an exception too.
However, there is a workaround that enables pagination, and we’ll cover in
the next section.
63
4. Pagination
Another advantage of pagination is that the amount of data sent from server
to client is minimized. By sending smaller pieces of data, we can generally
see an improvement in performance.
4.1. JPQL
4.2. Native
1. @Query(
2. value = “SELECT * FROM Users ORDER BY id”,
3. countQuery = “SELECT count(*) FROM Users”,
4. nativeQuery = true)
5. Page<User> findAllUsersWithPagination(Pageable pageable);
64
4.3. Spring Data JPA Versions Prior to 2.0.4
The above solution for native queries works fine for Spring Data JPA version
2.0.4 and later.
Prior to that version, when we try to execute such a query we’ll receive an
exception — the same one we described in the previous section on sorting.
1. @Query(
2. value = “SELECT * FROM Users ORDER BY id \n-- #pageable\n”,
3. countQuery = “SELECT count(*) FROM Users”,
4. nativeQuery = true)
5. Page<User> findAllUsersWithPagination(Pageable pageable);
In the above example, we add “\n– #pageable\n” as the placeholder for the
pagination parameter. This tells Spring Data JPA how to parse the query and
inject the pageable parameter. This solution works for the H2 database.
We’ve covered how to create simple select queries via JPQL and native SQL.
Next, we’ll show how to define additional parameters.
65
5. Indexed Query Parameters
There are two possible ways that we can pass method parameters to our
query. In this section, we’ll cover indexed parameters.
5.1. JPQL
For indexed parameters in JPQL, Spring Data will pass method parameters
to the query in the same order they appear in the method declaration:
For the above queries, the status method parameter will be assigned to
the query parameter with index 1, and the name method parameter will be
assigned to the query parameter with index 2.
5.2. Native
Indexed parameters for the native queries work exactly in the same way as
for JPQL:
1. @Query(
2. value = “SELECT * FROM Users u WHERE u.status = ?1”,
3. nativeQuery = true)
4. User findUserByStatusNative(Integer status);
66
6. Named Parameters
We can also pass method parameters to the query using named parameters.
We define these using the @Param annotation inside our repository method
declaration.
Each parameter annotated with @Param must have a value string matching
the corresponding JPQL or SQL query parameter name. A query with named
parameters is easier to read and is less error-prone in case the query needs
to be refactored.
6.1. JPQL
Note that in the above example, we defined our SQL query and method
parameters to have the same names, but it’s not required, as long as the
value strings are the same:
67
6.2. Native
For the native query definition, there is no difference how we pass a parameter
via the name to the query in comparison to JPQL — we use the @Param
annotation:
68
7. Collection Parameter
Let’s consider the case when the where clause of our JPQL or SQL query
contains the IN (or NOT IN) keyword
69
8. Update Queries with @Modifying
We can use the @Query annotation to modify the state of the database by
also adding the @Modifying annotation to the repository method.
8.1. JPQL
The repository method that modifies the data has two difference in
comparison to the select query — it has the @Modifying annotation and, of
course, the JPQL query uses update instead of select:
1. @Modifying
2. @Query(“update User u set u.status = :status where u.name = :name”)
3. int updateUserSetStatusForName(@Param(“status”) Integer status,
4. @Param(“name”) String name);
The return value defines how many rows the execution of the query updated.
Both indexed and named parameters can be used inside update queries.
8.2. Native
We can modify the state of the database also with a native query — we just
need to add the @Modifying annotation:
1. @Modifying
2. @Query(value = “update Users u set u.status = ? where u.name = ?”,
3. nativeQuery = true)
4. int updateUserSetStatusForNameNative(Integer status, String name);
70
8.3. Inserts
1. @Modifying
2. @Query(value = “insert into Users (name, age, email, status) values
3. (:name, :age, :email, :status)”,
4. nativeQuery = true)
5. void insertUser(@Param(“name”) String name, @Param(“age”) Integer
6. age,
7. @Param(“status”) Integer status, @Param(“email”) String email);
71
9. Dynamic Query
Often times, we’ll encounter the need for building SQL statements based
on conditions or data sets whose values are only known at runtime. And, in
those cases, we can’t just use a static query.
For example, let’s imagine a situation, where we need to select all the users
whose email is LIKE one from a set defined at runtime — email1, email2, …,
emailn:
In this case, we can’t just use the @Query annotation since we can’t provide
a static SQL statement.
72
9.2. Custom Repositories and the JPA Criteria API
Luckily for us, Spring provides a way for extending the base repository
through the use of custom fragment interfaces. We can then link them
together to create a composite repository.
73
As shown above, we leveraged the JPA Criteria API to build our dynamic
query.
Also, we need to make sure to include the Impl postfix in the class
name. Spring will search the UserRepositoryCustom implementation
as UserRepositoryCustomImpl. Since fragments are not repositories
by themselves, Spring relies on this mechanism to find the fragment
implementation.
Notice that all the query methods from section 2 – section 7 are in the
UserRepository. So now, we’ll integrate our fragment by extending the new
interface in the UserRepository:
74
10. Conclusion
As always, the complete code examples used in this chapter are available
over on Github.
75
8: Spring JDBC
76
1. Overview
In this chapter, we’ll go through practical use cases of the Spring JDBC
module.
All the classes in Spring JDBC are divided into four separate packages:
• core – the core functionality of JDBC. Some of the important classes under
this package include JdbcTemplate,SimpleJdbcInsert, SimpleJdbcCall and
NamedParameterJdbcTemplate.
• support – support classes for classes under core and object packages.
E.g. provides the SQLExceptiontranslation functionality.
77
2. Configuration
To begin with, let’s start with some simple configuration of the data source
(we’ll use a MySQL database for this example):
1. @Configuration
2. @ComponentScan(“com.baeldung.jdbc”)
3. public class SpringJdbcConfig {
4. @Bean
5. public DataSource mysqlDataSource() {
6. DriverManagerDataSource dataSource = new
7. DriverManagerDataSource();
8. dataSource.setDriverClassName(“com.mysql.jdbc.Driver”);
9. dataSource.setUrl(“jdbc:mysql://localhost:3306/springjdbc”);
10. dataSource.setUsername(“guest_user”);
11. dataSource.setPassword(“guest_password”);
12.
13. return dataSource;
14. }
15. }
1. @Bean
2. public DataSource dataSource() {
3. return new EmbeddedDatabaseBuilder()
4. .setType(EmbeddedDatabaseType.H2)
5. .addScript(“classpath:jdbc/schema.sql”)
6. .addScript(“classpath:jdbc/test-data.sql”).build();
7. }
78
Finally – the same can, of course, be done using XML configuring for the
datasource:
79
3. The JdbcTemplate and running queries
The JDBC template is the main API through which we’ll access most of the
functionality that we’re interested in:
Firstly, let’s start with a simple example to see what the JdbcTemplate can
do:
Notice the standard syntax of providing parameters – using the `?` character.
Next – let’s look at an alternative to this syntax.
80
3.2. Queries with Named Parameters
To get support for named parameters, we’ll use the other JDBC template
provided by the framework – the NamedParameterJdbcTemplate.
For instance, let’s look at below example that uses properties from a bean
to determine the named parameters:
81
3.3. Mapping Query Results to Java Object
Another very useful feature is the ability to map query results to Java objects
– by implementing the RowMapper interface.
For example – for every row returned by the query, Spring uses the row
mapper to populate the java bean:
Subsequently, we can now pass the row mapper to the query API and get
fully populated Java objects:
82
4. Exception Translation
Spring comes with its own data exception hierarchy out of the box – with
DataAccessException as the root exception – and it translates all underlying
raw exceptions to it.
83
5. JDBC operations using SimpleJdbc classes
5.1. SimpleJdbcInsert
Next, let’s provide the Column names and values, and execute the
operation
84
Further, to allow the database to generate the primary key, we can make
use of the executeAndReturnKey() API; we’ll also need to configure the actual
column that is auto-generated:
Also, let’s take a look at executing stored procedures – we’ll make use of the
SimpleJdbcCall abstraction:
85
6. Batch operations
86
We also have the option of batching operations with the
NamedParameterJdbcTemplate – batchUpdate() API.
This API is simpler than the previous one – no need to implement any extra
interfaces to set the parameters, as it has an internal prepared statement
setter to set the parameter values.
87
7. Spring JDBC with Spring Boot
1. <dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter-jdbc</artifactId>
4. </dependency>
5. <dependency>
6. <groupId>mysql</groupId>
7. <artifactId>mysql-connector-java</artifactId>
8. <scope>runtime</scope>
9. </dependency>
7.2. Configuration
Spring Boot configures the data source automatically for us. We just need
to provide the properties in a propertiesfile:
1. spring.datasource.url=jdbc:mysql://localhost:3306/springjdbc
2. spring.datasource.username=guest_user
3. spring.datasource.password=guest_password
That’s it, just by doing these configurations only, our application is up and
running and we can use it for other database operations.
88
8. Conclusion
Also, we looked into how we can quickly get started with Spring JDBC using
a Spring Boot JDBC starter.
V3.1
89