Data Access
Data Access
Data Access
Version 5.3.22
Back to index
1. Transaction Management
1.1. Advantages of the Spring Framework’s Transaction Support Model
1.1.1. Global Transactions
1.1.2. Local Transactions
1.1.3. Spring Framework’s Consistent Programming Model
1.2. Understanding the Spring Framework Transaction Abstraction
1.2.1. Hibernate Transaction Setup
1.3. Synchronizing Resources with Transactions
1.3.1. High-level Synchronization Approach
1.3.2. Low-level Synchronization Approach
1.3.3. TransactionAwareDataSourceProxy
1.4. Declarative Transaction Management
1.4.1. Understanding the Spring Framework’s Declarative Transaction Implementation
1.4.2. Example of Declarative Transaction Implementation
1.4.3. Rolling Back a Declarative Transaction
1.4.4. Configuring Different Transactional Semantics for Different Beans
1.4.5. <tx:advice/> Settings
1.4.6. Using @Transactional
@Transactional Settings
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 2/155
7/31/22, 5:50 PM Data Access
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 3/155
7/31/22, 5:50 PM Data Access
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 4/155
7/31/22, 5:50 PM Data Access
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 5/155
7/31/22, 5:50 PM Data Access
This part of the reference documentation is concerned with data access and the interaction
between the data access layer and the business or service layer.
1. Transaction Management
Comprehensive transaction support is among the most compelling reasons to use the Spring
Framework. The Spring Framework provides a consistent abstraction for transaction management
that delivers the following benefits:
A consistent programming model across different transaction APIs, such as Java Transaction
API (JTA), JDBC, Hibernate, and the Java Persistence API (JPA).
The following sections describe the Spring Framework’s transaction features and technologies:
Advantages of the Spring Framework’s transaction support model describes why you would
use the Spring Framework’s transaction abstraction instead of EJB Container-Managed
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 6/155
7/31/22, 5:50 PM Data Access
Transactions (CMT) or choosing to drive local transactions through a proprietary API, such as
Hibernate.
Understanding the Spring Framework transaction abstraction outlines the core classes and
describes how to configure and obtain DataSource instances from a variety of sources.
Synchronizing resources with transactions describes how the application code ensures that
resources are created, reused, and cleaned up properly.
Transaction bound event describes how you could use application events within a transaction.
Previously, the preferred way to use global transactions was through EJB CMT (Container
Managed Transaction). CMT is a form of declarative transaction management (as distinguished
from programmatic transaction management). EJB CMT removes the need for transaction-related
JNDI lookups, although the use of EJB itself necessitates the use of JNDI. It removes most but not
all of the need to write Java code to control transactions. The significant downside is that CMT is
tied to JTA and an application server environment. Also, it is only available if one chooses to
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 7/155
7/31/22, 5:50 PM Data Access
implement business logic in EJBs (or at least behind a transactional EJB facade). The negatives of
EJB in general are so great that this is not an attractive proposition, especially in the face of
compelling alternatives for declarative transaction management.
With programmatic transaction management, developers work with the Spring Framework
transaction abstraction, which can run over any underlying transaction infrastructure. With the
preferred declarative model, developers typically write little or no code related to transaction
management and, hence, do not depend on the Spring Framework transaction API or any other
transaction API.
In particular, you do not need an application server purely for declarative transactions
through EJBs. In fact, even if your application server has powerful JTA capabilities, you may
decide that the Spring Framework’s declarative transactions offer more power and a more
productive programming model than EJB CMT.
Typically, you need an application server’s JTA capability only if your application needs to
handle transactions across multiple resources, which is not a requirement for many
applications. Many high-end applications use a single, highly scalable database (such as
Oracle RAC) instead. Stand-alone transaction managers (such as Atomikos
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 8/155
7/31/22, 5:50 PM Data Access
Transactions and JOTM) are other options. Of course, you may need other application
server capabilities, such as Java Message Service (JMS) and Java EE Connector
Architecture (JCA).
The Spring Framework gives you the choice of when to scale your application to a fully
loaded application server. Gone are the days when the only alternative to using EJB CMT or
JTA was to write code with local transactions (such as those on JDBC connections) and face
a hefty rework if you need that code to run within global, container-managed transactions.
With the Spring Framework, only some of the bean definitions in your configuration file need
to change (rather than your code).
This is primarily a service provider interface (SPI), although you can use it programmatically from
your application code. Because PlatformTransactionManager is an interface, it can be easily
mocked or stubbed as necessary. It is not tied to a lookup strategy, such as
JNDI. PlatformTransactionManager implementations are defined like any other object (or bean) in
the Spring Framework IoC container. This benefit alone makes Spring Framework transactions a
worthwhile abstraction, even when you work with JTA. You can test transactional code much more
easily than if it used JTA directly.
Again, in keeping with Spring’s philosophy, the TransactionException that can be thrown by any
of the PlatformTransactionManager interface’s methods is unchecked (that is, it extends
the java.lang.RuntimeException class). Transaction infrastructure failures are almost invariably
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 9/155
7/31/22, 5:50 PM Data Access
fatal. In rare cases where application code can actually recover from a transaction failure, the
application developer can still choose to catch and handle TransactionException . The salient
point is that developers are not forced to do so.
As of Spring Framework 5.2, Spring also provides a transaction management abstraction for
reactive applications that make use of reactive types or Kotlin Coroutines. The following listing
shows the transaction strategy defined
by org.springframework.transaction.ReactiveTransactionManager :
The reactive transaction manager is primarily a service provider interface (SPI), although you can
use it programmatically from your application code. Because ReactiveTransactionManager is an
interface, it can be easily mocked or stubbed as necessary.
Propagation: Typically, all code within a transaction scope runs in that transaction. However,
you can specify the behavior if a transactional method is run when a transaction context
already exists. For example, code can continue running in the existing transaction (the
common case), or the existing transaction can be suspended and a new transaction created.
Spring offers all of the transaction propagation options familiar from EJB CMT. To read about
the semantics of transaction propagation in Spring, see Transaction Propagation.
Isolation: The degree to which this transaction is isolated from the work of other transactions.
For example, can this transaction see uncommitted writes from other transactions?
Timeout: How long this transaction runs before timing out and being automatically rolled back
by the underlying transaction infrastructure.
Read-only status: You can use a read-only transaction when your code reads but does not
modify data. Read-only transactions can be a useful optimization in some cases, such as when
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 10/155
7/31/22, 5:50 PM Data Access
These settings reflect standard transactional concepts. If necessary, refer to resources that
discuss transaction isolation levels and other core transaction concepts. Understanding these
concepts is essential to using the Spring Framework or any transaction management solution.
The TransactionStatus interface provides a simple way for transactional code to control
transaction execution and query transaction status. The concepts should be familiar, as they are
common to all transaction APIs. The following listing shows the TransactionStatus interface:
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
Regardless of whether you opt for declarative or programmatic transaction management in Spring,
defining the correct TransactionManager implementation is absolutely essential. You typically
define this implementation through dependency injection.
You can define a JDBC DataSource by creating a bean similar to the following:
</bean>
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 11/155
7/31/22, 5:50 PM Data Access
</bean>
If you use JTA in a Java EE container, then you use a container DataSource , obtained through
JNDI, in conjunction with Spring’s JtaTransactionManager . The following example shows what the
JTA and JNDI lookup version would look like:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
https://www.springframework.org/schema/jee/spring-jee.xsd">
</beans>
The JtaTransactionManager does not need to know about the DataSource (or any other specific
resources) because it uses the container’s global transaction management infrastructure.
The preceding definition of the dataSource bean uses the <jndi-lookup/> tag from
the jee namespace. For more information see The JEE Schema.
If you use JTA, your transaction manager definition should look the same, regardless of what
data access technology you use, be it JDBC, Hibernate JPA, or any other supported
technology. This is due to the fact that JTA transactions are global transactions, which can
enlist any transactional resource.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 12/155
7/31/22, 5:50 PM Data Access
In all Spring transaction setups, application code does not need to change. You can change how
transactions are managed merely by changing configuration, even if that change means moving
from local to global transactions or vice versa.
The DataSource bean definition is similar to the local JDBC example shown previously and, thus,
is not shown in the following example.
If the DataSource (used by any non-JTA transaction manager) is looked up through JNDI
and managed by a Java EE container, it should be non-transactional, because the Spring
Framework (rather than the Java EE container) manages the transactions.
The txManager bean in this case is of the HibernateTransactionManager type. In the same way as
the DataSourceTransactionManager needs a reference to the DataSource ,
the HibernateTransactionManager needs a reference to the SessionFactory . The following
example declares sessionFactory and txManager beans:
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
</bean>
If you use Hibernate and Java EE container-managed JTA transactions, you should use the
same JtaTransactionManager as in the previous JTA example for JDBC, as the following example
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 13/155
7/31/22, 5:50 PM Data Access
shows. Also, it is recommended to make Hibernate aware of JTA through its transaction
coordinator and possibly also its connection release mode configuration:
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>
Or alternatively, you may pass the JtaTransactionManager into your LocalSessionFactoryBean for
enforcing the same defaults:
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
created, reused, and cleaned up properly. The section also discusses how transaction
synchronization is (optionally) triggered through the relevant TransactionManager .
For example, in the case of JDBC, instead of the traditional JDBC approach of calling
the getConnection() method on the DataSource , you can instead use
Spring’s org.springframework.jdbc.datasource.DataSourceUtils class, as follows:
If an existing transaction already has a connection synchronized (linked) to it, that instance is
returned. Otherwise, the method call triggers the creation of a new connection, which is
(optionally) synchronized to any existing transaction and made available for subsequent reuse in
that same transaction. As mentioned earlier, any SQLException is wrapped in a Spring
Framework CannotGetJdbcConnectionException , one of the Spring Framework’s hierarchy of
unchecked DataAccessException types. This approach gives you more information than can be
obtained easily from the SQLException and ensures portability across databases and even across
different persistence technologies.
This approach also works without Spring transaction management (transaction synchronization is
optional), so you can use it whether or not you use Spring for transaction management.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 15/155
7/31/22, 5:50 PM Data Access
Of course, once you have used Spring’s JDBC support, JPA support, or Hibernate support, you
generally prefer not to use DataSourceUtils or the other helper classes, because you are much
happier working through the Spring abstraction than directly with the relevant APIs. For example, if
you use the Spring JdbcTemplate or jdbc.object package to simplify your use of JDBC, correct
connection retrieval occurs behind the scenes and you need not write any special code.
1.3.3. TransactionAwareDataSourceProxy
At the very lowest level exists the TransactionAwareDataSourceProxy class. This is a proxy for a
target DataSource , which wraps the target DataSource to add awareness of Spring-managed
transactions. In this respect, it is similar to a transactional JNDI DataSource , as provided by a
Java EE server.
You should almost never need or want to use this class, except when existing code must be called
and passed a standard JDBC DataSource interface implementation. In that case, it is possible that
this code is usable but is participating in Spring-managed transactions. You can write your new
code by using the higher-level abstractions mentioned earlier.
Most Spring Framework users choose declarative transaction management. This option has
the least impact on application code and, hence, is most consistent with the ideals of a non-
invasive lightweight container.
The Spring Framework’s declarative transaction management is made possible with Spring
aspect-oriented programming (AOP). However, as the transactional aspects code comes with the
Spring Framework distribution and may be used in a boilerplate fashion, AOP concepts do not
generally have to be understood to make effective use of this code.
The Spring Framework’s declarative transaction management is similar to EJB CMT, in that you
can specify transaction behavior (or lack of it) down to the individual method level. You can make
a setRollbackOnly() call within a transaction context, if necessary. The differences between the
two types of transaction management are:
Unlike EJB CMT, which is tied to JTA, the Spring Framework’s declarative transaction
management works in any environment. It can work with JTA transactions or local transactions
by using JDBC, JPA, or Hibernate by adjusting the configuration files.
You can apply the Spring Framework declarative transaction management to any class, not
merely special classes such as EJBs.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 16/155
7/31/22, 5:50 PM Data Access
The Spring Framework offers declarative rollback rules, a feature with no EJB equivalent. Both
programmatic and declarative support for rollback rules is provided.
The Spring Framework lets you customize transactional behavior by using AOP. For example,
you can insert custom behavior in the case of transaction rollback. You can also add arbitrary
advice, along with transactional advice. With EJB CMT, you cannot influence the container’s
transaction management, except with setRollbackOnly() .
The Spring Framework does not support propagation of transaction contexts across remote
calls, as high-end application servers do. If you need this feature, we recommend that you use
EJB. However, consider carefully before using such a feature, because, normally, one does not
want transactions to span remote calls.
The concept of rollback rules is important. They let you specify which exceptions (and throwables)
should cause automatic rollback. You can specify this declaratively, in configuration, not in Java
code. So, although you can still call setRollbackOnly() on the TransactionStatus object to roll
back the current transaction back, most often you can specify a rule
that MyApplicationException must always result in rollback. The significant advantage to this
option is that business objects do not depend on the transaction infrastructure. For example, they
typically do not need to import Spring transaction APIs or other Spring APIs.
Although EJB container default behavior automatically rolls back the transaction on a system
exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically
on an application exception (that is, a checked exception other than java.rmi.RemoteException ).
While the Spring default behavior for declarative transaction management follows EJB convention
(roll back is automatic only on unchecked exceptions), it is often useful to customize this behavior.
The most important concepts to grasp with regard to the Spring Framework’s declarative
transaction support are that this support is enabled via AOP proxies and that the transactional
advice is driven by metadata (currently XML- or annotation-based). The combination of AOP with
transactional metadata yields an AOP proxy that uses a TransactionInterceptor in conjunction
with an appropriate TransactionManager implementation to drive transactions around method
invocations.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 17/155
7/31/22, 5:50 PM Data Access
The following image shows a conceptual view of calling a method on a transactional proxy:
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 18/155
7/31/22, 5:50 PM Data Access
Java Kotlin
package x.y.service;
Java Kotlin
package x.y.service;
@Override
// ...
@Override
// ...
@Override
// ...
@Override
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 19/155
7/31/22, 5:50 PM Data Access
// ...
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the service object that we want to make transactional -->
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:attributes>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
<aop:config>
</aop:config>
</bean>
</bean>
</beans>
Examine the preceding configuration. It assumes that you want to make a service object,
the fooService bean, transactional. The transaction semantics to apply are encapsulated in
the <tx:advice/> definition. The <tx:advice/> definition reads as "all methods starting
with get are to run in the context of a read-only transaction, and all other methods are to run with
the default transaction semantics". The transaction-manager attribute of the <tx:advice/> tag is
set to the name of the TransactionManager bean that is going to drive the transactions (in this
case, the txManager bean).
You can omit the transaction-manager attribute in the transactional advice ( <tx:advice/> ) if
the bean name of the TransactionManager that you want to wire in has the
name transactionManager . If the TransactionManager bean that you want to wire in has any
other name, you must use the transaction-manager attribute explicitly, as in the preceding
example.
The <aop:config/> definition ensures that the transactional advice defined by the txAdvice bean
runs at the appropriate points in the program. First, you define a pointcut that matches the
execution of any operation defined in the FooService interface ( fooServiceOperation ). Then you
associate the pointcut with the txAdvice by using an advisor. The result indicates that, at the
execution of a fooServiceOperation , the advice defined by txAdvice is run.
The expression defined within the <aop:pointcut/> element is an AspectJ pointcut expression.
See the AOP section for more details on pointcut expressions in Spring.
A common requirement is to make an entire service layer transactional. The best way to do this is
to change the pointcut expression to match any operation in your service layer. The following
example shows how to do so:
<aop:config>
</aop:config>
In the preceding example, it is assumed that all your service interfaces are defined in
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 21/155
7/31/22, 5:50 PM Data Access
Now that we have analyzed the configuration, you may be asking yourself, "What does all this
configuration actually do?"
The configuration shown earlier is used to create a transactional proxy around the object that is
created from the fooService bean definition. The proxy is configured with the transactional advice
so that, when an appropriate method is invoked on the proxy, a transaction is started, suspended,
marked as read-only, and so on, depending on the transaction configuration associated with that
method. Consider the following program that test drives the configuration shown earlier:
Java Kotlin
fooService.insertFoo(new Foo());
The output from running the preceding program should resemble the following (the Log4J output
and the stack trace from the UnsupportedOperationException thrown by
the insertFoo(..) method of the DefaultFooService class have been truncated for clarity):
<!-- ... the insertFoo(..) method is now being invoked on the proxy -->
<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [org.apache.commo
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 22/155
7/31/22, 5:50 PM Data Access
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)
To use reactive transaction management the code has to use reactive types.
Spring Framework uses the ReactiveAdapterRegistry to determine whether a method return
type is reactive.
The following listing shows a modified version of the previously used FooService , but this time the
code uses reactive types:
Java Kotlin
package x.y.service;
Java Kotlin
package x.y.service;
@Override
// ...
@Override
// ...
@Override
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 23/155
7/31/22, 5:50 PM Data Access
// ...
@Override
// ...
Imperative and reactive transaction management share the same semantics for transaction
boundary and transaction attribute definitions. The main difference between imperative and
reactive transactions is the deferred nature of the latter. TransactionInterceptor decorates the
returned reactive type with a transactional operator to begin and clean up the transaction.
Therefore, calling a transactional reactive method defers the actual transaction management to a
subscription type that activates processing of the reactive type.
Another aspect of reactive transaction management relates to data escaping which is a natural
consequence of the programming model.
Method return values of imperative transactions are returned from transactional methods upon
successful termination of a method so that partially computed results do not escape the method
closure.
Reactive transaction methods return a reactive wrapper type which represents a computation
sequence along with a promise to begin and complete the computation.
A Publisher can emit data while a transaction is ongoing but not necessarily completed.
Therefore, methods that depend upon successful completion of an entire transaction need to
ensure completion and buffer results in the calling code.
The recommended way to indicate to the Spring Framework’s transaction infrastructure that a
transaction’s work is to be rolled back is to throw an Exception from code that is currently
executing in the context of a transaction. The Spring Framework’s transaction infrastructure code
catches any unhandled Exception as it bubbles up the call stack and makes a determination
whether to mark the transaction for rollback.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 24/155
7/31/22, 5:50 PM Data Access
In its default configuration, the Spring Framework’s transaction infrastructure code marks a
transaction for rollback only in the case of runtime, unchecked exceptions. That is, when the
thrown exception is an instance or subclass of RuntimeException . ( Error instances also, by
default, result in a rollback). Checked exceptions that are thrown from a transactional method do
not result in rollback in the default configuration.
You can configure exactly which Exception types mark a transaction for rollback, including
checked exceptions by specifying rollback rules.
Rollback rules
Rollback rules determine if a transaction should be rolled back when a given exception is
thrown, and the rules are based on patterns. A pattern can be a fully qualified class name or
a substring of a fully qualified class name for an exception type (which must be a subclass
of Throwable ), with no wildcard support at present. For example, a value
of "javax.servlet.ServletException" or "ServletException" will
match javax.servlet.ServletException and its subclasses.
Rollback rules may be configured in XML via the rollback-for and no-rollback-
for attributes, which allow patterns to be specified as strings. When using @Transactional ,
rollback rules may be configured via
the rollbackFor / noRollbackFor and rollbackForClassName / noRollbackForClassName attributes,
which allow patterns to be specified as Class references or strings, respectively. When an
exception type is specified as a class reference its fully qualified name will be used as the
pattern. Consequently, @Transactional(rollbackFor = example.CustomException.class) is
equivalent to @Transactional(rollbackForClassName = "example.CustomException") .
You must carefully consider how specific the pattern is and whether to include package
information (which isn’t mandatory). For example, "Exception" will match nearly
anything and will probably hide other rules. "java.lang.Exception" would be correct
if "Exception" were meant to define a rule for all checked exceptions. With more
unique exception names such as "BaseBusinessException" there is likely no need to
use the fully qualified class name for the exception pattern.
Furthermore, rollback rules may result in unintentional matches for similarly named
exceptions and nested classes. This is due to the fact that a thrown exception is
considered to be a match for a given rollback rule if the name of thrown exception
contains the exception pattern configured for the rollback rule. For example, given a
rule configured to match on com.example.CustomException , that rule would match
against an exception named com.example.CustomExceptionV2 (an exception in the
same package as CustomException but with an additional suffix) or an exception
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 25/155