d12g

Blog von Daniel Grewing

Spring Boot – Zugriff auf zwei Datenbanken

24. April 2016 Softwareentwicklung

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";
    }
}

Auf den Weg zur Superintelligenz

10. April 2016 Allgemein

11252626214_7f0e0613c3_z

Vor wenigen Wochen gingen Berichte über ein Duell im Spiel Go zwischen einem der besten Spieler der Welt, Lee Sedol,  und der Software von Google AlphaGo durch die Medien. Das Spiel Go ist noch komplexer als Schach und es wurde lange daran gezweifelt, dass eine Software so bald in der Lage sein würde einen Profispieler schlagen zu können. Nach drei Partien stand es am Ende 3:1 für AlphaGo.

Einige waren überrascht, dass der Sieg so deutlich für Google ausging. Mich überraschte vielmehr, dass es bereits jetzt, 2016, soweit war. In Superintelligenz beschreibt Nick Bostrom die Gefahren bei der Entwicklung der künstlichen Intelligenz. Sein Buch erschien 2014 und Bostrom ist eine bekannte Kompetenz auf dem Gebiet der Zukunftsforschung und Superintelligenz.

Superintelligenz (wörtl. Über-Intelligenz) bezeichnet Wesen oder Maschinen mit dem Menschen überlegener Intelligenz. Der Begriff findet insbesondere im Transhumanismus und im Bereich der Künstlichen Intelligenz Verwendung. Ein tatsächlich geistig überlegenes Wesen, das die Kriterien einer Superintelligenz erfüllt, ist nach heutigem Kenntnisstand nicht bekannt.

https://de.wikipedia.org/wiki/Superintelligenz

In einem Vergleich macht er deutlich, bei welchen Spielen und ab welchem Jahr der Mensch kein Gegner mehr für einen Computerspieler war. Interessant ist, dass Bostrom für das Spiel Go 2014 eine Computerintelligenz noch als amateurhaften Spieler einstufte. Zwei Jahre später kann ich mir gar nicht mehr vorstellen, dass ein menschlicher Spieler jemals eine Chance gegen AlphaGo oder eine andere Software haben wird. Zum Vergleich wann eine Software bei bekannten Spielen ein übermenschlicher Gegner war: Backgammon 1979, Dame im Jahr 1994 und im Schach besiegte 1997 Deep Blue von IBM den Schachweltweister Kasparow.

Es ist also viel eher eingetreten. Es kann natürlich sein, dass Bostrom eine falsche Einschätzung über den aktuellen Stand der KI-Forschung gehabt hat. Es kann aber auch bedeuten, dass die großen Internetunternehmen wie Google, Facebook oder Apple an Systemen arbeiten von denen wir nichts ahnen und sie dann plötzlich der Öffentlichkeit vorstellen. Ich denke wir werden in den nächsten Jahren noch einige Überraschungen im Bereich der künstlichen Intellegenz erleben.

Bostrom beschreibt ein sehr düsteres Bild in Superintelligenz und für ihn scheint es nur eine Frage der Zeit bis eine Superintelligenz die Macht über die Menschheit übernimmt. Seine Schlussfolgerungen scheinen mir durchaus logisch und seine Motivation ist auch eine Diskussion in der Gesellschaft anzuregen (der erste Gipfel in Deutschland findet im April statt). Ich bin aber skeptisch, dass eine KI-Software so schnell zu einer Superintelligenz reifen kann und in der Lage wäre, die Geschicke der Menschheit zu lenken. Aber vielleicht ist es doch bald soweit und wir werden von einer Superintelligenz überrascht, die es als ihre Lebensaufgabe sieht möglichst viele Büroklammern herzustellen.