Let us integrate Hibernate 5 to the Spring 5 application using the following steps:
- Convert the Maven project ch12-hiber to a Spring Boot application by adding the following Spring Boot 2.0.0.M2 starter POM dependencies, such as webflux, actuator, and JDBC, with some support plugins such as the MySQL connector.
- Hibernate 5 has no dedicated starter POM in Spring Boot 2.0, but it is by default contained in the Spring Data JPA starter POM. Since adding the ORM framework is covered by the Spring MVC module, it is mandatory to include the Spring MVC starter POM in the Maven configuration, as follows:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
- Inside a new org.packt.hiber.core package, add a Bootstrap class that disables the JPA autoconfiguration process, because JPA is bound with Hibernate 5 in Spring Boot, making it impossible to use Hibernate 5 as a standalone solution. Even without JPA, still ensure that the @EnableTransactionManagement annotation is applied to the Bootstrap class:
@SpringBootApplication(exclude = JpaRepositoriesAutoConfiguration.class) @EnableTransactionManagement public class HiberBootApplication extends SpringBootServletInitializer { // refer to sources }
- Inside its srcmain esources directory, create an application.properties file that contains the same server-related and database properties. Also, include the actuator endpoint details for project monitoring and deployment. Most importantly, add in here all the needed Hibernate details to be fetched by some API classes in @Configuration later:
server.port=8087 server.servlet.context-path=/ch12-hiber spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/hrs?autoReconnect=true&useSSL=true&serverSslCert=classpath:config/spring5packt.crt spring.datasource.username=root spring.datasource.password=spring5mysql spring.datasource.hikari.connection-timeout=60000 management.port=8087 management.address=localhost management.context-path=/appdetails // refer to sources #Hibernate 5 Details hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect hibernate.show_sql=true hibernate.format_sql=true
- Also, include logback.xml and the config folder in the srcmain esources directory, from the previous projects.
- Copy the entity model Department from the previous Spring JPA project.
- Before implementing the Hibernate transactions inside the org.packt.hiber.core.config package, add the following configuration class which builds the org.springframework.orm.hibernate5.LocalSessionFactoryBean, org.springframework.orm.hibernate5.HibernateTransactionManager, and org.springframework.orm.hibernate5.HibernateTemplate packages and injects these beans in to the container. The Hibernate properties from the application.properties file are fetched by these APIs through the property placeholder variant org.springframework.core.env.Environment, as follows:
@Configuration @EnableWebFlux public class HiberConfig { @Autowired private Environment environment; @Bean public Properties hibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect")); properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql")); properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.show_sql")); return properties; } @Bean("sessionFactory") public LocalSessionFactoryBean localSessionFactory( DataSource dataSource, Properties hibernateProperties) { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setPackagesToScan( "org.packt.hiber.core.model.data"); sessionFactory.setHibernateProperties(hibernateProperties); return sessionFactory; } @Bean public HibernateTransactionManager db1TransactionManager( DataSource dataSource, LocalSessionFactoryBean localSessionFactory) { HibernateTransactionManager txManager = new HibernateTransactionManager(); txManager.setSessionFactory( localSessionFactory.getObject()); txManager.setDataSource(dataSource); return txManager; } @Bean public HibernateTemplate hibernateTemplate( SessionFactory sessionFactory) { return new HibernateTemplate(sessionFactory); } }
- Let's now build a Hibernate transaction manager for the department table schema of the hrs database. The following are the template methods for the department @Repository transactions found in the org.packt.hiber.core.dao package:
public interface DepartmentDao { public List<Department> getAllDepts(); public List<Department> getDeptsByName(String name); public List<Department> getDeptsByDeptid(Integer deptid); public Department getDeptById(Integer id); public void saveDept(Department dept); }
- Implement the preceding template methods using the generated org.hibernate.SessionFactory package and its createQuery() method. Drop this implementation class inside the org.packt.hiber.core.dao.impl package as follows:
@Repository public class DepartmentDaoImpl implements DepartmentDao{ @Autowired private SessionFactory sessionFactory; @Override public List<Department> getAllDepts() { return sessionFactory.openSession() .createQuery("select d from Department d", Department.class).getResultList(); } @Override public List<Department> getDeptsByName(String name) { return sessionFactory.openSession() .createQuery("select d from Department d where d.name LIKE '%:name%'", Department.class) .setParameter("name", name).getResultList(); } @Override public List<Department> getDeptsByDeptid(Integer deptid) { return sessionFactory.openSession() .createQuery("select d from Department d where d.deptid = :deptid", Department.class) .setParameter("deptid", deptid).getResultList(); } @Override public Department getDeptById(Integer id) { return sessionFactory.openSession() .createQuery("select d from Department d where d.id = :id", Department.class) .setParameter("id", id).getSingleResult(); } @Override public void saveDept(Department dept) { sessionFactory.openSession().persist(dept); } }
- Now, implement the service layer by having a set of services found in the org.packt.hiber.core.service package, as follows:
public interface DepartmentService { public List<Department> getAllDeptList(); public List<Department> getDeptsByName(String name); public List<Department> getDeptsByDeptid(Integer deptid); public Department getDeptById(Integer id); public void saveDept(Department dept); }
- Inside the org.packt.hiber.core.service.impl package, implement the preceding service methods using the DepartmentDao repository transactions, as follows:
@Service public class DepartmentServiceImpl implements DepartmentService{ @Autowired private DepartmentDao departmentDaoImpl; @Override public List<Department> getAllDeptList() { return departmentDaoImpl.getAllDepts(); } @Override public List<Department> getDeptsByName(String name) { return departmentDaoImpl.getDeptsByName(name); } // refer to sources }
Avoid using the @Transaction annotation since Hibernate transaction management has been enabled by @EnableTransactionManagement during Bootstrap. The @Transaction annotation is appropriate for JPA transactions only.
- To test Hibernate services, implement the following RESTful services through HiberController in the org.packt.hiber.core.controller package, as follows:
@RestController public class HiberController { @Autowired private DepartmentService departmentServiceImpl; @GetMapping(value="/listDepts", produces= MediaType.APPLICATION_JSON_VALUE) public List<Department> listDepts() { return departmentServiceImpl.getAllDeptList(); } @GetMapping(value="/selectDept/{id}", produces= MediaType.APPLICATION_JSON_VALUE) public Department selectDept(@PathVariable("id") Integer id) { return departmentServiceImpl.getDeptById(id); } @GetMapping(value="/selectDeptByDeptid/{deptid}", produces= MediaType.APPLICATION_JSON_VALUE) public List<Department>selectDeptByDeptid( @PathVariable("deptid") Integer deptid) { return departmentServiceImpl.getDeptsByDeptid(deptid); } }
- Save all files.
- Build and deploy the project with the clean spring-boot:run -U command.
- Finally, open a browser and execute a sample RESTful service, as shown in the following screenshot: