This examples shows how to use declarative transactions in JPA based Spring application. We will use Spring's JpaTransactionManager which is an implementation of PlatformTransactionManager (check out JDBC based Spring Declarative Transaction example ).
Example
A Generic Dao Interface
public interface Dao<T> {
void save(T t);
T load(long id);
void delete(long id);
void update(T t);
List<T> loadAll();
}
A JPA Entity
@Entity
public class Person {
@Id
@GeneratedValue
private long id;
private String firstName;
private String lastName;
private String address;
.............
}
The DAO implementation
package com.logicbig.example;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class PersonDaoJpaImpl implements Dao<Person> {
@PersistenceContext
private EntityManager em;
@Override
public void save(Person person) {
em.persist(person);
}
@Override
public Person load(long id) {
Person person = em.find(Person.class, id);
return person;
}
@Override
public void delete(long id) {
Person employee = em.find(Person.class, id);
em.remove(employee);
}
@Override
public void update(Person person) {
em.merge(person);
}
@Override
public List<Person> loadAll() {
List<Person> persons = em.createQuery("Select t from Person t")
.getResultList();
return persons;
}
}
Note that, we used JPA's @PersistenceContext annotation on EntityManager . That way we don't have to create a new EntityManager through EntityManagerFactory each time (as compared to the last example). In above code, we are requesting a transactional EntityManager (also called "shared EntityManager" because it is a shared, thread-safe proxy for the actual transactional EntityManager) to be injected instead of the factory.
The Service Layer
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
@Service
public class PersonService {
@Autowired
private Dao<Person> dao;
@Transactional
public void savePerson(Person person) {
try {
dao.save(person);
} catch (DataAccessException e) {
e.printStackTrace();
}
}
public List<Person> getAllPersons() {
try {
return dao.loadAll();
} catch (DataAccessException e) {
e.printStackTrace();
}
return null;
}
public Person getPersonById(long id) {
try {
return dao.load(id);
} catch (DataAccessException e) {
e.printStackTrace();
}
return null;
}
@Transactional
public void deletePerson(long id) {
try {
dao.delete(id);
} catch (DataAccessException e) {
e.printStackTrace();
}
}
@Transactional
public void updatePerson(Person person) {
try {
dao.update(person);
} catch (DataAccessException e) {
e.printStackTrace();
}
}
}
Note that we used javax.transaction.Transactional . Instead of that, we could have used org.springframework.transaction.annotation.Transactional without any other changes.
The Example Client
@Component
public class ExampleClientBean {
@Autowired
PersonService personService;
public void run() {
System.out.println("'Persisting persons'");
Person person = Person.create("Dana", "Whitley", "464 Gorsuch Drive");
personService.savePerson(person);
person = Person.create("Robin", "Cash", "64 Zella Park");
personService.savePerson(person);
System.out.println("'loading all persons'");
List<Person> allPersons = personService.getAllPersons();
System.out.println("Persons loaded: " + allPersons);
person = personService.getPersonById(2);
System.out.println("Person loaded by id 2 : " + person);
System.out.println("'updating person address with id 2'");
person.setAddress("111 Yellow Hill");
personService.updatePerson(person);
System.out.println("'Deleting person by id 1'");
personService.deletePerson(1);
System.out.println("'loading all persons'");
allPersons = personService.getAllPersons();
System.out.println("Persons loaded: " + allPersons);
}
}
persistence.xml
src/main/resources/META-INF/persistence.xml<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="example-unit" transaction-type="RESOURCE_LOCAL">
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
</properties>
</persistence-unit>
</persistence>
Java Config and main class
package com.logicbig.example;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
@Configuration
@ComponentScan
@EnableTransactionManagement
public class AppConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPersistenceUnitName("example-unit");
return factory;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(ExampleClientBean.class).run();
EntityManagerFactory emf = context.getBean(EntityManagerFactory.class);
emf.close();
}
}
Output
'Persisting persons'
'loading all persons'
Persons loaded: [Person{id=1, firstName='Dana', lastName='Whitley', address='464 Gorsuch Drive'}, Person{id=2, firstName='Robin', lastName='Cash', address='64 Zella Park'}]
Person loaded by id 2 : Person{id=2, firstName='Robin', lastName='Cash', address='64 Zella Park'}
'updating person address with id 2'
'Deleting person by id 1'
'loading all persons'
Persons loaded: [Person{id=2, firstName='Robin', lastName='Cash', address='111 Yellow Hill'}]
Example ProjectDependencies and Technologies Used: - spring-context 5.0.2.RELEASE: Spring Context.
- spring-orm 5.0.2.RELEASE: Spring Object/Relational Mapping.
- hibernate-core 5.2.12.Final: The core O/RM functionality as provided by Hibernate.
Implements javax.persistence:javax.persistence-api version 2.1 - h2 1.4.196: H2 Database Engine.
- JDK 1.8
- Maven 3.3.9
|