Spring / Spring Data Access
JdbcTemplate class provides many convenience methods for doing things such as converting database data into primitives or objects, executing prepared and callable statements, and providing custom database error handling.
The Spring JDBC Template has the following advantages compared with standard JDBC.
The Spring JDBC template allows to clean-up the resources automatically, e.g. release the database connections.
The Spring JDBC template converts the standard JDBC SQLExceptions into RuntimeExceptions. This allows the programmer to react more flexible to the errors. The Spring JDBC template converts also the vendor specific error messages into better understandable error messages.
There are 2 ways to access Hibernate with Spring.
- Inversion of Control with a Hibernate Template and Callback.
- Extending HibernateDAOSupport and Applying an AOP Interceptor node.
Use Spring's SessionFactory called LocalSessionFactory to integrate Spring and HIbernate. The integration process is of 3 steps.
- Configure the Hibernate SessionFactory.
- Extend a DAO Implementation from HibernateDaoSupport.
- Wire in Transaction Support with AOP.
It supports declarative transaction management.
It provides a consistent programming model across different transaction APIs such as JTA, JDBC, Hibernate, JPA, and JDO.
It provides a simpler API for programmatic transaction management than a number of complex transaction APIs such as JTA.
It integrates very well with Spring's various data access abstractions.
Declarative transaction management is preferred over programmatic transaction management though it is less flexible than programmatic transaction management, which allows you to control transactions through your code.
This exception hierarchy aims to let user code find and handle the kind of error encountered without knowing the details of the particular data access API in use (for example, JDBC).
This class is a runtime exception, there is no need for user code to catch it or subclasses if any error is to be considered fatal (the usual case).
Mark the DAO class with @Repository annotation.
Entity manager can be configured by @PersistenceContext at property level.
Spring supports the following ORMS.
- Hibernate.
- iBatis.
- JPA (Java Persistence API).
- TopLink.
- JDO (Java Data Objects).
- MongoDB, Open-source document database.
- Cassandra Database that provides scalability and high availability without compromising performance.
- Redis structure server wherein keys can contain strings, hashes, lists, sets, and sorted sets.
- HBase Hadoop database, a distributed and scalable big data store.
The Spring callbacks in JdbcTemplate are PreparedStatementCallback, ResultSetExtractor, RowCallbackHandler and RowMapper.
JPA is a specification while Hibernate is a particular implementation of that specification.
Spring Data JPA is on top of JPA adding another layer of abstraction, standardizing the design for the support of your Persistence Layer in a Spring context. Those defined interfaces (known to Spring) provide the services that the framework handles using JPA to serve the results.
Spring Data JPA is not an implementation or JPA provider, it's just an abstraction used to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores. Spring Data JPA always requires the JPA provider such as Hibernate or Eclipse Link.
Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that is actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.
Spring DAO classes throw exceptions that are subclasses of org.springframework.dao. DataAccessException.
Spring translates technology-specific exceptions like SQLException to its own exception class hierarchy with the DataAccessException as the root exception that are generic and easy to understand. These exceptions wrap the original exception.
SQLExceptionTranslator is a strategy interface that translates between SQLExceptions and Spring's data access strategy-agnostic DataAccessException hierarchy.
The returned DataAccessException is supposed to contain the original SQLException as root cause.
JpaRepository extends PagingAndSortingRepository that extends CrudRepository.
CrudRepository mainly provides CRUD operations.
PagingAndSortingRepository provide methods to perform pagination and sorting of records.
JpaRepository provides JPA related methods such as flushing the persistence context and deleting of records in batch.
Due to their inheritance nature, JpaRepository will have all the behaviors of CrudRepository and PagingAndSortingRepository. So if you don't need the repository to have the functions provided by JpaRepository and PagingAndSortingRepository , use CrudRepository.
spring-data adds powerful and useful API that helps with complex queries.
Spring JPA will provide you abstraction from writing SQL and even some HQL using query method declaration. Spring JPA shines with its query generation but when you want a purely hibernate solution you can customize as needed as spring JPA is still based on hibernate.
Use Spring JdbcTemplate if you don't want to access your database schema via a domain model. Using JPA you need to make sure that database schema maps correctly to the domain model.
Performance is almost similar at both spring JdbcTemplate and JPA.
PreparedStatementCreator is one of the most commonly used interfaces for writing data to the database. createPreparedStatement() is a method that can be used to create and return PreparedStatement from the Connection argument, and exception handling is automatically taken care of. When this interface is implemented, a different interface SqlProvider can also be implemented which has a method called getSql().
This method is useful for providing sql strings to the JdbcTemplate. It does not handle SQLExceptions.
SQLProvider is mainly used for debugging. It has only one method called getSql() and it is implemented using PreparedStatementCreator implementers.
BatchPreparedStatementSetter is used to update more than a single row in bulk.This interface provides two methods,
- setValues( PreparedStatement ps, int i) throws SOL exception.
- int getBatchSize.
For better performance and easy implementation JDBC can be used with the template class called JdbcTemplate.
- JdbcTemplate.
- NamedParameterJdbcTemplate.
- SimpleJdbcTemplate
- SimpleNativeJdbcExtractor.
- C3P0NativeJdbcExtractor .
- CommonsDbcpNativeJdbcExtractor .
- JBossNativeJdbcExtractor.
Global transactions helps manage multiple transactional resources like relational databases and message queue. Global transactions are managed through JTA and JNDI.
Local transactions are resource-specific like JDBC connection. Local Transactions can interact with multiple transactional resources.
Use rollback-for and no-rollback-for attributes with transactional definition.
- ISOLATION_DEFAULT: default isolation.
- ISOLATION_READ_COMMITTED: dirty reads are prevented, non-repeatable and phantom reads are allowed.
- ISOLATION_READ_UNCOMMITTED : dirty reads are allowed, no-repeatable and phantom reads are allowed.
- ISOLATION_REPEATABLE_READ : dirty reads and non-repeatable reads are prevented but phantom reads are allowed.
- ISOLATION_SERIALIZABLE : dirty , non- repeatable reads and phantom reads are prevented.
There are 7 propagation levels in spring.
Use rollback-for and no-rollback-for attributes with transactional definition.
- Isolation.
- Propagation.
- Timeout.
- Read-only status.
The Spring Framework provides a consistent abstraction for transaction management that delivers the following benefits:
Provides a consistent programming model across different transaction APIs such as JTA, JDBC, Hibernate, JPA, and JDO.
Supports declarative transaction management.
Provides a simpler API for programmatic transaction management than a number of complex transaction APIs such as JTA.
Integrates very well with Spring's various data access abstractions.
Declarative transaction management provides least impact on application code and hence is most consistent with the ideals of a non-invasive lightweight container.
Transactional annotation is the convenient and readable and is currently the recommended way to handle transactions in Spring.
By using @Transactional, many important aspects such as transaction propagation are handled automatically.
Declarative transaction support uses AOP (Aspect Oriented Programming) as its foundation.
@Transactional annotation is based on AOP concept.
When you annotate a method with @Transactional, Spring dynamically creates a proxy that implements the same interface(s) as the class you are annotating. And when clients make calls into your object, the calls are intercepted and the behaviors gets injected via the proxy mechanism.
@Transactional annotation works similar to transactions in EJB.
You can use PreparedStatement to avoid SQL injection in Java code. Use of the PreparedStatement for executing SQL queries not only provides better performance but also shield your Java and J2EE application from SQL Injection attack.
@RepositoryRestResource annotation exposes a data repository as a RESTFul resource. This annotiation is similar to @RestController annotation in Spring MVC.
@RestController annotation renders as Restful resource within a Controller while @RepositoryRestResource annotation exposes repository itself as a RESTful resource.
Unit testing can be achieved by mocking all JPA data API that we invoke.
However the unit testing for spring data respositories is not required since we don't write any API implementations. Integration testing is more ideal than unit testing.
- Serializable,
- Repeatable reads,
- Read committed,
- and read uncommitted.
In a Repeatable Read isolation level, new rows can be inserted into the dataset.
In a Serializable isolation level all the rows are locked for the duration of the transaction, no insert,update or delete is allowed.
This is the highest isolation level.
With a lock-based concurrency control DBMS implementation, serializability requires read and write locks (acquired on selected data) to be released at the end of the transaction. Also range-locks must be acquired when a SELECT query uses a ranged WHERE clause, especially to avoid the phantom reads phenomenon.
When using non-lock based concurrency control, no locks are acquired; however, if the system detects a write collision among several concurrent transactions, only one of them is allowed to commit.
Spring ISOLATION_DEFAULT uses the default isolation level of the underlying datastore.
PROPAGATION_REQUIRED is the default propagation property of @Transactional annotation.
By default configuration only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked and the transaction will still be commited in case of checked exceptions.
To enable rollbacking on checked exceptions add the parameter rollBackFor to the @Transactional attribute, for example, rollbackFor=Exception.class.
@Transactional(rollbackFor = Exception.class)
This annotation excludes repository interfaces from being picked up and prevents getting an instance being created.
The common usage of this annotation is when providing an extended base interface for all repositories in combination with a custom repository base class to implement methods declared in that intermediate interface. In this case you typically derive your concrete repository interfaces from the intermediate one but prevents creating a Spring bean for the intermediate interface.
Leverage batch processing to process the work off-line in batch.
Use Real-time asynchronous processing such as fine-grained timers or asynchronous event triggers (such as JMS) to pass responsibility from on-line to back-end function.
When one transaction reads changes made by another transaction that has not yet been committed it is called dirty read. It is dangerous and unusual to use this type of transaction because the read data might get rolled back.
Both non-repeatable and phantom reads have to do with data modification operations from a different transaction, which were committed after your transaction began, and then read by your transaction.
Non-repeatable reads are when your transaction reads committed UPDATES from another transaction. The same row now has different values than it did when your transaction began.
Phantom reads are similar but when reading from committed INSERTS and/or DELETES from another transaction. There are new rows or rows that have disappeared since you began the transaction.
Dirty reads are similar to non-repeatable and phantom reads, but relate to reading UNCOMMITTED data, and occur when an UPDATE, INSERT, or DELETE from another transaction is read, and the other transaction has NOT yet committed the data. It is reading "in progress" data, which may not be complete, and may never actually be committed.
Two phase commit is used in distributed environment where multiple transaction take part in distributed transaction process.
In two phase commit, commit or rollback is performed in 2 phases:
Commit request phase: In this phase main process or coordinator process send precommit request to all other process that it has completed its process successfully and ready to commit if all the votes are 'yes' then they go ahead for next phase. And if 'No' then rollback is performed.
Commit phase: Based on the acknowledgement vote if all the votes are yes then commit is done otherwise rollbacked.
JNDI creates a connection pool. Connection pool is an environment on the server where JNDI and Database encapsulated to for Type4 connectivity.
JDBC: A Java API that enables Java programs to execute SQL statements. This allows Java programs to interact with any SQL-compliant database.
If you want to delegate managed transactions to your application server and handle complex transactions across multiple resources you need to use the JtaTransactionManager, but I believe it is not needed in most cases, JJpaTransactionManager, is the best choice.
JTA is global transaction while JPA is local.
Yes. @Transactional annotation has the property transactionManager
which can be set to specify which transaction manager to be used.
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory1" /> <qualifier value="TM1"/> </bean> <bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory2" /> <qualifier value="TM2"/> </bean>
public class DAOService { @Transactional("TM1") public void doSomethingWithTransactionManager1() { ... } @Transactional("TM2") public void doSomethingWithTransactionManager2(() { ... } }
HibernateTransactionManager manages transactions on top of a single Hibernate SessionFactory. If your application uses only a JDBC-compliant database to store data (that is, no ERP, JMS queue, file system, etc. is involved) that you access using Hibernate, you can use a HibernateTransactionManager in your application.
If however, you have business operations that can modify multiple data stores at the same time and you need to ensure data consistency across all the stores, you will need to use JTA transactions. JTA support is provided either by JavaEE containers like JBoss, WebLogic or WebSphere or third-party JTA providers like Atomikos or Bitronix.
It is about making your code depend on either JPA or Hibernate when using Hibernate or JPA transaction manager.
javax.persistence.EntityManager
is a JPA (Java EE) standard interface, while org.hibernate.SessionFactory
is a Hibernate proprietary interface. Using EntityManager instead of SessionFactory makes your classes not depend on Hibernate.
Using the JPA-way instead of the Hibernate-way is considered as best practice. JPA way will still depend on Hibernate as the JPA provider, however, when you want to change to another JPA provider, it will be easy.
JPA-interfaces are considered more stable than the Hibernate.
DataSourceTransactionManager is for JDBC while HibernateTransactionManager is for Hibernate.
DataSourceTransactionManager needs a reference to the DataSource, the HibernateTransactionManager needs a reference to the SessionFactory.
Yes. The Spring Framework's declarative transaction management works in any environment. It can work with JTA transactions or local transactions using JDBC, JPA, Hibernate or JDO.
Yes, only public methods. If you annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings.
Consider the use of AspectJ if you need to annotate non-public methods.
Spring recommends annotating concrete classes and its methods with the @Transactional annotation, as opposed to annotating interfaces.
You can place the @Transactional annotation on an interface (or an interface method), but this works only if you are using interface-based proxies.
Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class="true") or the weaving-based aspect ( mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy.
The proxy-target-class attribute controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If proxy-target-class is set to true, class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, standard JDK interface-based proxies are created.
<aop:config proxy-target-class="true"> <!-- other beans defined here... --> </aop:config>
You may use 'proxy-target-class="true"' on
- Default propagation setting is PROPAGATION_REQUIRED.
- Isolation level is ISOLATION_DEFAULT.
- The transaction is read/write.
- Transaction timeout defaults to the default timeout of the underlying transaction system, none if timeouts are not supported.
- Any RuntimeException triggers rollback, and any checked Exception does not.
Propagation is the ability to decide how the business methods should be encapsulated in both logical or physical transactions.
There are 7 different propagation levels.
REQUIRED states that the same transaction will be used if there is an already opened transaction in the current bean method execution context and it creates a new transaction if one already does not exists.
REQUIRES_NEW states that a new physical transaction will always be created by the container.
The NESTED makes nested Spring transactions to use the same physical transaction but sets save-points between nested invocations so inner transactions may also rollback independently of outer transactions. This is applicable only to JDBC.
The MANDATORY states that an existing opened transaction must already exist. If not an exception will be thrown by the container.
The NEVER states that an existing opened transaction must not already exist. If a transaction exists an exception will be thrown by the container.
The NOT_SUPPORTED will execute outside of the scope of any transaction. If an opened transaction already exists it will be paused.
The SUPPORTS will execute in the scope of a transaction if an opened transaction already exists. If there isn't an already opened transaction the method will execute anyway but in a non-transactional way.
Spring Data's mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store. It makes it easy to use data access technologies, relational and non-relational databases, map-reduce frameworks, and cloud-based data services.
Spring Data provides Abstractions (interfaces) that can be used irrespective of underlying data source.
interface EmployeeRepository extends CrudRepository<Employee, Long> {
Using the simple Employee repository, perform insert, update, delete and retrieval of EMPLOYEE entities from the database - without writing any database dependent code.
The @Transactional(propagation = Propagation.NESTED)
annotation is used to define a nested transactional scope in a Spring Boot application. When a method is annotated with this annotation, a nested transaction is created within the current transaction.
The nested transaction behaves as an independent transaction and can be rolled back separately from the outer transaction. If the nested transaction fails, only the changes made within the nested transaction are rolled back, while the outer transaction remains unaffected.