d12g

Blog von Daniel Grewing

Spring Boot – Zugriff auf zwei Datenbanken

| Keine Kommentare

Mit Spring Boot kann man Spring Anwendungen per “convention over configuration” erstellen. Eine Webanwendung mit MVC-Logik und Datenbankzugriff ist schnell erstellt. Für ein Projekt benötigte ich eine Anwendung, die auf zwei unterschiedliche Datenbanken (MySql und PostgreSQL) zugreifen konnte.
Da der Zugriff auf zwei Datenbanken nur über weitere Konfigurationen möglich ist, musste ich recht lange suchen und probieren, bis ich eine schöne Lösung gefunden hatte. Diese möchte hier vorstellen.
Bei diesem Beispiel soll eine Anwendung Benutzerdaten aus zwei Datenbanken laden und anzeigen. In der MySql-Datenbank liegt die Tabelle User, in der PostgreSQL-Datenbank die Tabelle Benutzer. Ein Controller soll jeweils einen Datensatz laden und auf einer Webseite anzeigen.

Der Screenshot zeigt die Struktur des Eclipseprojekts:
spring-boot-projekt_twoDbs

Das Spring-Projekt basiert auf dieser pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>de.rockworm</groupId>
	<artifactId>springBootTwoDb</artifactId>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.3.RELEASE</version>
	</parent>
	<dependencies>
		<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>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>9.1-901.jdbc4</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<properties>
		<java.version>1.7</java.version>
	</properties>
	<repositories>
		<repository>
			<id>spring-milestone</id>
			<url>https://repo.spring.io/libs-release</url>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-milestone</id>
			<url>https://repo.spring.io/libs-release</url>
		</pluginRepository>
	</pluginRepositories>
</project>

Der Datenbankzugriff wird über eine Java-Bean- und eine DataAccessObject-Klasse erstellt:
Für user auf der MySql-Datenbank:

@Entity
@Table(name="user")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	 
	@Column
	private String 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;
	}
}

@Transactional
public interface UserDao extends CrudRepository<User, Integer> {
}

Für benutzer auf der PostgreSQL-Datenbank:

@Entity
@Table(name="benutzer")
public class Benutzer {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	 
	@Column
	private String nickname;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
}
@Transactional
public interface BenutzerDao extends CrudRepository<Benutzer, Integer> {

}

Die Konfiguration für den Zugriff auf die beiden Datenbanken erfolgt in den Klassen MySqlConfig.java und PostgreSqlConfig.java

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "customerEntityManagerFactory", transactionManagerRef = "customerTransactionManager")
class MySqlConfig {

    @Bean
    PlatformTransactionManager customerTransactionManager() {
	return new JpaTransactionManager(customerEntityManagerFactory().getObject());
    }

    @Bean
    LocalContainerEntityManagerFactoryBean customerEntityManagerFactory() {

	HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
	jpaVendorAdapter.setGenerateDdl(true);

	LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

	factoryBean.setDataSource(dataSource());
	factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
	factoryBean.setPackagesToScan(MySqlConfig.class.getPackage().getName());

	return factoryBean;
    }

    @Bean(name = "datasource.mysql")
    @ConfigurationProperties(prefix = "datasource.mysql")
    public DataSource dataSource() {
	return DataSourceBuilder.create().build();
    }
}
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "orderEntityManagerFactory", transactionManagerRef = "orderTransactionManager")
class PostgreSqlConfig {

    @Bean
    PlatformTransactionManager orderTransactionManager() {
	return new JpaTransactionManager(orderEntityManagerFactory().getObject());
    }

    @Bean
    LocalContainerEntityManagerFactoryBean orderEntityManagerFactory() {

	HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
	vendorAdapter.setGenerateDdl(true);

	LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

	factoryBean.setDataSource(dataSource());
	factoryBean.setJpaVendorAdapter(vendorAdapter);
	factoryBean.setPackagesToScan(PostgreSqlConfig.class.getPackage().getName());

	return factoryBean;
    }

    @Bean(name = "datasource.postgres")
    @ConfigurationProperties(prefix = "datasource.postgres")
    public DataSource dataSource() {
	return DataSourceBuilder.create().build();
    }
}

In beiden Klassen wird in den Annotationen Bean und ConfigurationProperties ein Prefix genutzt, welches sich in der application.properties wiederfindet.

server.port = 8833

datasource.mysql.driverClassName=com.mysql.jdbc.Driver
datasource.mysql.url=jdbc:mysql://172.16.1.207/dev-springboot
datasource.mysql.username=user
datasource.mysql.password=pass
datasource.mysql.testOnBorrow=true
datasource.mysql.validationQuery=SELECT 1

datasource.postgres.driverClassName=org.postgresql.Driver
datasource.postgres.url = jdbc:postgresql://172.16.1.204/dev-springboot
datasource.postgres.username = user
datasource.postgres.password = pass
datasource.postgres.testOnBorrow=true
datasource.postgres.validationQuery=SELECT 1

spring.jpa.hibernate.ddl-auto=update

Im Controller können nun Datensätze aus beiden Datenbanken abgerufen und an das Model übergeben werden:

@Controller
public class IndexController {

    @Autowired
    private UserDao userDao;

    @Autowired
    private BenutzerDao benutzerDao;
    
    @RequestMapping("/index")
    public String index(Model model) {

    	User user1 = userDao.findOne(1);
    	Benutzer benutzer1 = benutzerDao.findOne(1);
    	
    	model.addAttribute("user", user1);
    	model.addAttribute("benutzer", benutzer1);
	
	return "index";
    }
}

Hinterlasse eine Antwort

Pflichtfelder sind mit * markiert.