- Home>
- Spring Framework>
- Building backend API with Spring data, Hibernate, JPA.
In this post, I’ll go over the setup of a sample backend RESTful API which utilizes Spring and Hibernate to simplify database operations and transaction management over a relational database.
Source code is available on GitHub: https://github.com/taithienbo/bookapp
Datasource is how you tell Spring how to connect to your backend database.
The below configurations are for starting up a H2 embedded database which supports Oracle SQL flavor for integration tests.
@Bean public DataSource dataSource() { EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder( ); DataSource dataSource = embeddedDatabaseBuilder.setType( EmbeddedDatabaseType.H2 ).setName( "testdb;" + "mode=Oracle" ) .build(); return dataSource; }
The hsqldb library has a nice utitlity – the DatabaseManageSwing to manage the test database via a GUI, which I find convenience and helpful for debugging.
@Bean public Server startDbManager() throws SQLException { DatabaseManagerSwing.main(new String[] { "--url", "jdbc:h2:mem:testdb" }); return Server.createWebServer( ); }
For production, you probably want to connect to a standalone database such as MySQL or Oracle. As this sample application is based on a real web application that gets deployed to a WebLogic server, a common pattern is configuring the datasource on the actual server and lookup the configurations via JNDI as shown below.
@Bean(destroyMethod = "") public DataSource dataSource() { try { Context context = new InitialContext( ); DataSource dataSource = ( DataSource ) context.lookup( appDatabasePropsLoader.getJndiDatasourceName() ); return dataSource; } catch ( NamingException e ) { // unable to resolve data source info // log the exception LOGGER.error( "Failed to resolve data source.", e); return null; } }
An EntityManager manages the life cycles of entities within a persistent context. For each record in the database with an identity, there exists one entity instance in the persistence context.
An EntityManagerFactory creates EntityManager objects. More than one options exist for configuring an EntityManagerFactory. The LocalContainerEntityManagerFactoryBean is more flexible over the other option, the LocalEntityManagerFactoryBean. Per Spring docs, the LocalEntityManagerFactoryBean has limited configuration power, whereas the LocalContainerEntityManager bean is more powerful in which you can override the location of the persistence.xml file, specify location of JDBC data sources …
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl( false ); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter( vendorAdapter ); factory.setPackagesToScan( "com.tbo.bookapp.domain" ); factory.setDataSource( dataSource() ); Properties properties = new Properties( ); properties.put( Environment.CURRENT_SESSION_CONTEXT_CLASS, org.hibernate.context.internal .ThreadLocalSessionContext.class); return factory; }
The above codes specify Hibernate as the JPA provider, tell the EntityManager where to look for entities to manage, and the corresponding data source. In addition, it applies Hibernate specific settings via the setJpaProperties() method on the factory.
The below codes configure NamedParameterJdbcTemplate for using in cases where we need to provide our own custom queries in addition to Spring provided implementations of the CRUD operations. The NamedParameterJdbcTemplate allows the use of named parameters which I find makes the codes easier to read and maintain.
@Bean public NamedParameterJdbcTemplate namedParameterJdbcTemplate() { return new NamedParameterJdbcTemplate( dataSource() ); }
Lastly, we configure Spring PlatformTransactionManger for managing transactions. Spring provides a nice documentation on transaction management including the differences between global vs local transaction managers and other options. I recommend going over this documentation to understand how Spring manages transaction and to pick the best option depending on your use cases.
@Bean public PlatformTransactionManager platformTransactionManager() { JpaTransactionManager txManager = new JpaTransactionManager( ); txManager.setEntityManagerFactory( entityManagerFactory().getObject()); txManager.afterPropertiesSet(); return txManager; }