Welcome to the Spring ORM Example Tutorial. Today we will look into Spring ORM example using Hibernate JPA transaction management. I will show you a very simple example of Spring standalone application with following features.
I have used in-memory database for Spring ORM example, so no need for any database setup (but you can change it to any other database in the spring.xml datasource section). This is a Spring ORM standalone application to minimize all dependencies (but you can easily change it to a web project by configuration if you get familiar with spring). NOTE: For Spring AOP based Transactional (without @Transactional annotation) method resolution approach please check this tutorial: Spring ORM AOP Transaction Management. Below image shows our final Spring ORM example project. Let’s go through each of the Spring ORM example project components one by one.
Below is our final pom.xml file having Spring ORM dependencies. We have used Spring 4 and Hibernate 4 in our Spring ORM example.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hu.daniel.hari.learn.spring</groupId>
<artifactId>Tutorial-SpringORMwithTX</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<!-- Generic properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<!-- SPRING & HIBERNATE / JPA -->
<spring.version>4.0.0.RELEASE</spring.version>
<hibernate.version>4.1.9.Final</hibernate.version>
</properties>
<dependencies>
<!-- LOG -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JPA Vendor -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- IN MEMORY Database and JDBC Driver -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring-context
and spring-orm
as Spring dependencies.hibernate-entitymanager
for Hibernate as JPA implementation. hibernate-entitymanager
is dependent on hibernate-core
this why we don’t have to put hibernate-core in pom.xml explicitly. It’s being pulled into our project through maven transitive dependencies.We can use standard JPA annotations for mapping in our model beans because Hibernate provides JPA implementation.
package hu.daniel.hari.learn.spring.orm.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer id;
private String name;
public Product() {
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + "]";
}
}
We use @Entity
and @Id
JPA annotations to qualify our POJO as an Entity and to define it’s primary key.
We create a very simple DAO class that provides persist and findALL methods.
package hu.daniel.hari.learn.spring.orm.dao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
@Component
public class ProductDao {
@PersistenceContext
private EntityManager em;
public void persist(Product product) {
em.persist(product);
}
public List<Product> findAll() {
return em.createQuery("SELECT p FROM Product p").getResultList();
}
}
@PersistenceContext
annotation that indicate dependency injection to an EntityManager. Spring injects a proper instance of EntityManager according to the spring.xml configuration.Our simple service class has 2 write and 1 read methods - add, addAll and listAll.
package hu.daniel.hari.learn.spring.orm.service;
import hu.daniel.hari.learn.spring.orm.dao.ProductDao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional
public void add(Product product) {
productDao.persist(product);
}
@Transactional
public void addAll(Collection<Product> products) {
for (Product product : products) {
productDao.persist(product);
}
}
@Transactional(readOnly = true)
public List<Product> listAll() {
return productDao.findAll();
}
}
@Transactional
Spring annotation. The listAll method only reads the database so we set the @Transactional annotation to read-only for optimisation.Our spring ORM example project java classes are ready, let’s look at our spring bean configuration file now. spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:p="https://www.springframework.org/schema/p"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:tx="https://www.springframework.org/schema/tx"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
https://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
<context:component-scan base-package="hu.daniel.hari.learn.spring" />
<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
<context:annotation-config />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem://productDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
p:dataSource-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
EntityManagerFactory
that will used by the application to obtain an EntityManager. Spring supports 3 different ways to do this, we have used LocalContainerEntityManagerFactoryBean
for full JPA capabilities. We set LocalContainerEntityManagerFactoryBean
attributes as:
Our spring ORM JPA Hibernate example project is ready, so let’s write a test program for our application.
public class SpringOrmMain {
public static void main(String[] args) {
//Create Spring application context
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//Get service from context. (service's dependency (ProductDAO) is autowired in ProductService)
ProductService productService = ctx.getBean(ProductService.class);
//Do some data operation
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//Test transaction rollback (duplicated key)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//Test element list after rollback
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
You can see how easily we can start the Spring container from a main method. We are getting our first dependency injected entry point, the service class instance. ProductDao
class reference injected to the ProductService
class after the spring context is initialized. After we got ProducService
instance, we can test it’s methods, all method call will be transactional due to Spring’s proxy mechanism. We also test rollback in this example. If you run above spring ORM example test program, you will get below logs.
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Note that the second transaction is rolled back, this why product list didn’t changed. If you use log4j.properties
file from attached source, you can see what’s going on under the hood. References: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html You can download the final Spring ORM JPA Hibernate Example project from below link and play around with it to learn more.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
Exception in thread “main” java.lang.IllegalArgumentException: Unknown entity: hu.daniel.hari.learn.spring.orm.spring.orm.model.Product How to resolve it
- gs
If you encounter the below issue, No bean named ‘transactionManager’ is defined simply add the bean value next to transaction annotation @Transactional(value = “transactionManager”) public void add(Product product) { productDao.persist(product); } You can also declare the @Transactional annotation at class leve
- Uday
Followed your spring.xml config but I get this error: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’: Failed to introspect bean class [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] for lookup method metadata: could not find class that it depends on; nested exception is java.lang.NoClassDefFoundError: javax/persistence/SharedCacheMode maybe it’s because of this line here where I get an error ref=“entityManagerFactory” is red and the error : or delimiter expected, got ‘entityManagerFactory’
- yggdras
Please mention where to add dialect for hibernate … I wonder how your application is working without specifying dialect…
- Hassan
NICE ONE. if we have an association, it will be different let me take a example in your Product Class let say we have set Of customers ------------------------------- @Entity public class Product { @Id private Integer id; private String name; @OneToMany(fetch type LAZY) set cust= new HashSet(0); // set and get } WE HAVE DAO METHOD LIKE THIS PUBLIC Set getCustomerstBasedOnProductId(Inetger id){ Product pr=entityManger.get(1);//it will return ProductObject Set cuts=pr.getCustomers();// it will return set of Customers for(Customers c : cuts){ Sop(c.getProductName());// here we will getException saying that "Exception in thread “main” org.hibernate.LazyInitializationException: " } } Exception: why bcoz after execution of get() method Session object will be closed so proxy Object will be deleted from the Session so that we will get this kind of exception … how can i resolve this problem please help me
- sai
Since you defined @PersistenceContext in ProductDao, every method will be there own transaction. So why to define @Transactional on method of ProductService ?
- Simron
Exception in thread “main” java.lang.NoClassDefFoundError: antlr/RecognitionException This lib is into hibernate .jar, but the application don’t recognizes…
- Rodrigo Marini
Excellent. In which directory I should create the spring.xml file?
- Carlos
Exception in thread “main” javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process ‘persist’ call at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:278) at com.sun.proxy.$Proxy8.persist(Unknown Source) at com.dao.ProductDao.Persist(ProductDao.java:19) at com.service.ProductService.add(ProductService.java:19) at SpringOrmMain.main(SpringOrmMain.java:22)
- Mithilesh
Thanks Daniel, This article was very useful.
- Pankaj