Graph database + Relational database = ❤

Neo4j 4.1.6 is the last iteration before 4.2.0 which was officially released on Jan. 25th, 2017. One would say, “Why not just use 4.2.0?” Well, 4.2.0 requires Spring Boot 1.5.0 which does not have a release version just yet. So let’s focus on the latest Neo4j release version and Spring Boot 1.4.X.

Firstly, install Neo4j. Follow the instructions found on this page. If on a Mac simply run brew install neo4j . When Neo4j is done installing run neo4j start in terminal to start up the database. That is all that is needed to install Neo4j.

Let’s dive into the Spring Boot portion. Open build.gradle file and add the following dependencies:

compile "org.springframework.data:spring-data-neo4j-rest:3.4.6.RELEASE"

compile "org.springframework.data:spring-data-neo4j:4.1.6.RELEASE"

compile "org.neo4j:neo4j-ogm-core:2.0.6"

compile "org.neo4j:neo4j-ogm-http-driver:2.0.6"

For this use case, the communication method to the Neo4j database has to be a RESTful call. To achieve this the HTTP driver can be used. There are two other driver options: Bolt and Embedded. This post will focus on using the HTTP driver.

Refresh the gradle dependencies by running ./gradlew clean build in the root directory of theSpring Boot project. After this, we can start configuring the application.

We will need to edit existing / add new annotations within the Java file that contains the application configuration.

Application Class Annotations

@ComponentScan(values = {"com.example"})

This tells Spring Boot to scan all project packages. com.example holds all the classes that pertain to both relational and graph databases. This includes @Controller, @Service, @Entity, and @Repository .

@EnableAutoConfiguration(exclude = {Neo4jDataAutoConfiguration.class, DataSourceAutoConfiguration.class})

This explicitly tell Spring Boot how to set up our datasources. This is why Neo4jDataAutoConfiguration.class and DataSourceAutoConfiguration.cass are excluded.

Currently the application class should look like the following:

package com.example; import ... @Configuration

@ComponentScan(values = {"com.example"})

@EnableAutoConfiguration(exclude = {Neo4jDataAutoConfiguration.class, DataSourceAutoConfiguration.class})

public class DemoApplication { public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

}

Datasource Configuration Class

The next step will be to create a configuration file that will configures both the MySQL and Neo4j databases. The annotations for this class file are the following:

@Configuration

@EnableNeo4jRepositories(basePackages = "com.example.graph")

@EnableJpaRepositories(basePackages = "com.example.relational")

@EnableTransactionManagement

@Configuration annotation tells Spring that “This is a configuration file please load it!”. This will generate bean definitions at runtime

annotation tells Spring that “This is a configuration file please load it!”. This will generate bean definitions at runtime @EnableNeo4jRepositories(basePackages = "com.example.graph) will tell Spring Boot to enable all repositories under the package com.example.graph to be a neo4j graph repository

will tell Spring Boot to enable all repositories under the package to be a neo4j graph repository @EnableJpaRepositories(basePackages = "com.example.relational") will tell Spring Boot to enable all repositories under the package com.example.relational to be relational repositories.

will tell Spring Boot to enable all repositories under the package to be relational repositories. @EnableTransactionManagement allows us to use annotation-driven transaction management

Now that annotations are set up let’s beginning building out our configuration class.

public class DatasourceConfig extends Neo4jConfiguration

Our class needs to extend Neo4jConfiguration so configuration for Neo4j settings can be set explicitly.

Next, create a configuration bean that will configure the Neo4j database.

@Bean

public org.neo4j.ogm.config.Configuration getConfiguration() {

org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();

config

.driverConfiguration()

.setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver")

.setURI("http://YOUR_USERNAME:YOUR_PASSWORD@localhost:7474");

return config;

}

This method wires up the Neo4j database with Spring Boot. Setting the location of the database with a username and password and we also state which driver we are using. In this case, using the HttpDriver .

The next bean sets the configuration settings in the Neo4j session that is used to interact with the Neo4j database.

@Bean

public SessionFactory getSessionFactory() {

return new SessionFactory(getConfiguration(), "com.example.graph");

}

Another Neo4j bean that needs to be configured is the getSession bean. This allows Neo4j to integrate with the Spring Boot application.

@Bean

public Session getSession() throws Exception {

return super.getSession();

}

Now that Neo4j is almost taken care of let’s set up the relational datasource. In this case, MySQL is used. To achieve this, creating a datasource bean as well as a entity manager bean is needed.

@Primary

@Bean(name = "dataSource")

@ConfigurationProperties(prefix = "spring.datasource")

public DataSource dataSource() {

return DataSourceBuilder

.create()

.driverClassName("com.mysql.jdbc.Driver")

.build();

}



@Primary

@Bean

@Autowired

public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {

LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();

entityManagerFactory.setDataSource(dataSource);

entityManagerFactory.setPackagesToScan("com.example.core");

entityManagerFactory.setJpaDialect(new HibernateJpaDialect());

Map<String, String> jpaProperties = new HashMap<>();

jpaProperties.put("hibernate.connection.charSet", "UTF-8");

jpaProperties.put("spring.jpa.hibernate.ddl-auto", "none");

jpaProperties.put("spring.jpa.hibernate.naming-strategy", "org.springframework.boot.orm.jpa.SpringNamingStrategy");

jpaProperties.put("hibernate.bytecode.provider", "javassist");

jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");

jpaProperties.put("hibernate.hbm2ddl.auto", "none");

jpaProperties.put("hibernate.order_inserts", "true");

jpaProperties.put("hibernate.jdbc.batch_size", "50");



entityManagerFactory.setJpaPropertyMap(jpaProperties);

entityManagerFactory.setPersistenceProvider(new HibernatePersistenceProvider());

return entityManagerFactory;

}

These beans are declared primary because the MySQL database should take precedence over the Neo4j database.

The JPA properties can be tweaked to your liking as well!

The last thing that needs to set up are the transaction managers. These manage the transactions for the relational database, Neo4j database, and then the manager for the overall application.

@Autowired

@Bean(name = "neo4jTransactionManager")

public Neo4jTransactionManager neo4jTransactionManager(Session sessionFactory) {

return new Neo4jTransactionManager(sessionFactory);

}



@Autowired

@Primary

@Bean(name = "mysqlTransactionManager")

public JpaTransactionManager mysqlTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory)

throws Exception {

return new JpaTransactionManager(entityManagerFactory.getObject());

}





@Autowired

@Bean(name = "transactionManager")

public PlatformTransactionManager transactionManager(Neo4jTransactionManager neo4jTransactionManager, JpaTransactionManager mysqlTransactionManager) {

return new ChainedTransactionManager(

mysqlTransactionManager,

neo4jTransactionManager

);

}

The ChainedTransactionManager allows for multiple transaction managers. This means that any transaction that occurs will be delegated to each manager. If the first manager fails, the second manager will then be invoked.

I have created a repository with a demo application that can be found on GitHub.

That’s it! The application now has access to both MySQL and Neo4j! Like / comment. All constructive criticism welcomed!

This is my first blog post ever! Wahoo!