Datenbankzugriffe in Java-Applikationen mit Hilfe - RWTH

Werbung
Simon Wirtz
Seminarvortrag WS 13/14
Oktober 2013
© 2012 TravelTainment
Datenbankzugriffe in Java-Applikationen
mit Hilfe des Spring Frameworks
Inhaltsübersicht

1. Motivation und Einleitung

2. Java Database Connectivity
2.1 Anwendung

2.2 Problematik der Technologie
3. Objektrelationale Abbildungen

3.1 Hibernate

3.1.1 Anwendung

3.1.2 Vergleich zu JDBC
© 2012 TravelTainment


Inhaltsübersicht
4. Spring

4.1 Kerntechnologien

4.2 Spring Data Access/Integration



4.2.1 Spring JDBC

4.2.1.1 Das JdbcTemplate

4.2.1.2 Vorteile der Technologie
4.2.2 Spring ORM

4.2.2.1 Nutzung von Hibernate mit Spring

4.2.2.2 Vorteile von Spring ORM für Hibernate
5. Fazit
© 2012 TravelTainment

1. Motivation und Einleitung

Viele Computeranwendungen arbeiten mit Datenbanken

Datenbankzugriff in Applikationen über verschiedene
Tools und Technologien

In Java:
ORM
Spring
• primäre DB-Schnittstelle
• Fortgeschritten und objektorientiert
• Weitere Erleichterungen
© 2012 TravelTainment
JDBC
© 2012 TravelTainment
Kapitel 2
JDBC
2. Java Database Connectivity

Datenbankschnittstelle der Java-Plattform

Am 19. Februar 1997 erstmals veröffentlicht

Neueste Version: JDBC 4.1

Hauptfunktionalität:
SQLAbfragen
senden
Mit den
Ergebnissen
arbeiten
© 2012 TravelTainment
Verbindung
zu DB
aufbauen
2.1 Anwendung
private String url = "...", dbName = "...",
userName = "..", password = "...";
private Connection connection = null;
private Statement statement = null;
private ResultSet resultSet = null;
//load driver and connect to db
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {...}
try {
connection = DriverManager.getConnection(url + dbName,
userName, password);
} catch (SQLException ex) {...}
Verbindungsaufbau
try {
statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM car;");
printResult();
} catch (SQLException ex) {...}
Abfrage senden
while (resultSet.next()) {
Car car = new Car();
car.setHorsePower(resultSet.getInt("horsepower"));
car.setId(resultSet.getInt("id"));
//set more attributes
System.out.println(car);
}
} catch (SQLException ex) {...}
Verarbeiten
© 2012 TravelTainment
try {
2.2 Problematik der Technologie
JDBC arbeitet SQLbasiert!
Geschäftslogik <
Verwaltung
Aufwändiges
Ressourcenmanagement
•Sich wiederholender
Prozess
Exceptionhandling
bei allen APIAufrufen
© 2012 TravelTainment
Manuelles
Überführen von
Datenbankeintrag in
Objekt und
umgekehrt
© 2012 TravelTainment
Kapitel 3
ORM
3. Objektrelationale Abbildung

Erlaubt das Ablegen von Objekten in einer Datenbank

Schicht zwischen Anwendung und Datenbank

Behandelt Unverträglichkeit zwischen Objekten und
relationalen Datenbanken
ORM
1

NAME
Simon
Beispiel Java: Java Persistence API
DESCRIPTION
Test
AGE
21
© 2012 TravelTainment
ID
3.1 Hibernate

Implementierung der Java Persistence API

Neuste Version im März 2013 veröffentlicht: 4.2.0

Mapping der POJOs über XML oder Annotationen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Parameterloser Konstruktor ist Pflicht
import javax.persistence.*;
@Entity
public class Person {
@Id
@GeneratedValue (strategy=GenarationType.AUTO)
private int id;
@Column(name="firstName", nullable=false, unique = true)
private String name;
private String description;
private Integer age;
public Person(){}
/* getter and setter */
}
Importieren des
Packages
Annotieren des
POJOs mit @Entity
und einer @Id
@Column zur
Spezifizierung der
Spaltendefinition
© 2012 TravelTainment

Konfigurationsdatei

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
hibernate.cfg.xml
Beinhaltet Daten für SessionFactory
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost/hibernate
</property>
<property name="connection.username">user</property>
<property name="connection.password">password</property>
Datenbankspezifikation
<!-- JDBC connection pool -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="model.Person"/>
</session-factory>
</hibernate-configuration>
Weitere
Spezifikationen wie
„Dialect“
Annotierte Klassen
© 2012 TravelTainment

3.1.1 Anwendung
private SessionFactory factory = null;
private Configuration configuration = null;
private ServiceRegistry serviceRegistry = null;
configuration = new Configuration().configure();
serviceRegistry = new ServiceRegistryBuilder().
applySettings(configuration.getProperties()).
buildServiceRegistry();
factory = configuration.buildSessionFactory(serviceRegistry);
Erzeugen der
SessionFactory

Session wird aus SessionFactory bezogen

Ausführen einer Query über Session

Methode ist in Transaktion gehüllt
© 2012 TravelTainment
Session session = factory.withOptions().openSession();
session.beginTransaction();
Query query = session.createQuery("from Person");
List<Person> persons = (List<Person>)query.list();
session.getTransaction().commit();
3.1.2 Vergleich zu JDBC
Beispiel: Abfragen eines Objekts aus der Datenbank
private ResultSet doQuery(String query){
ResultSet result = null;
try{
connectToDb();
stmt = conn.createStatement();
result = stmt.executeQuery(query);
} catch (Exception e){...}
return result;
public Person getById(Integer id){
}
Session session = factory.withOptions().openSession();
session.beginTransaction();
String select = "from Person p where p.id = " + id;
Query query = session.createQuery(select);
Person p = (Person) query.uniqueResult();
session.getTransaction().commit();
return p;
}
© 2012 TravelTainment
public Person getById(Integer id){
String query = "SELECT * from person where id= "+id;
ResultSet result = doQuery(query):
Person person = null;
try{
while(result.next()){
String name = result.getString("name");
String desc = result.getString("description");
Integer age = result.getInt("age");
Integer idValue = result.getInt("id");
person = new Person(name, desc, age, idValue);
}
closeConnAndStmt();
} catch(SQLException sqlE){...}
return person;
}
3.1.2 Vergleich zu JDBC
Geschäftslogik steht
mehr im Vordergrund
(Sinn der
Technologie)
OO-Konzept wird
verfolgt
© 2012 TravelTainment
Weniger
Verwaltungsaufwand
Überführung der DBEinträge in Objekte
nicht nötig
© 2012 TravelTainment
Kapitel 4
Spring
4 Spring


Modular aufgebautes Framework (ca. 20 Module)
Aktuelle Version: 3.2 vom 13.12.2012
Ziel:

Entwicklung mit Java/JEE vereinfachen

gute Programmierpraktiken fördern
© 2012 TravelTainment


Dependeny Injection bzw. Inversion of Control

IoC-Container beinhaltet alle wichtigen ApplikationsKomponenten (Beans) inklusive Abhängigkeiten

Beans können aus ApplicationContext bezogen
werden
© 2012 TravelTainment
4.1 Kerntechnologien
Bean-Definition

1. XML
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the 'ref' attribute -->
<property name="beanOne" ref="anotherExampleBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>

2. Annotationen
@Component
public class ExampleBean {
// other attributes and methods
}
© 2012 TravelTainment
@Autowired
private AnotherBean beanOne;
private int integerProperty;
4.2 Spring Data Access / Integration
© 2012 TravelTainment
Wie gestaltet Spring das
Arbeiten mit JDBC und Hibernate
angenehmer und einfacher?
© 2012 TravelTainment
Spring JDBC
4.2.1.1 Das JdbcTemplate

Einschränkungen in JDBC

Springs Lösungsansatz: JdbcTemplate

Threadsafe, kann in allen DAOs genutzt werden

Benötigt DataSource, das Verbindungsparameter definiert:
© 2012 TravelTainment
<bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db"/>
<property name="username" value="user_xy" />
<property name="password" value="pw_xy" />
</bean>
Nutzung des JdbcTemplates
Injizieren der DataSource-Bean in DAO:

@Repository
public class ExampleDao implements IExampleDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the ExampleDao
}
JdbcTemplate stellt ca. 100 Methoden bereit

execute(sql: String)

update()-Methoden
public void insertCar(Car car) {
String query = "INSERT INTO car (id, make, horsepower)"+
"VALUES(?,?,?);";
jdbcTemplate.update(query, "DEFAULT", car.getMake(),
car.getHorsePower());
}
© 2012 TravelTainment

Vereinfachtes Mapping

RowMapper-Interface
private static final class CarMapper implements RowMapper<Car> {
@Override
public Car mapRow(ResultSet resultSet, int i) throws SQLException {
Car result = new Car();
result.setMake(resultSet.getString("make"));
result.setHorsePower(resultSet.getInt("horsepower"));
result.setId(resultSet.getInt("id"));
result.setSeats(resultSet.getInt("seats"));
result.setType(resultSet.getString("type"));
return result;
}
Implementierung
public Car getCarById(int id) {
String query = "SELECT * FROM car WHERE id=?";
Car car = jdbcTemplate.queryForObject(query, new CarMapper(), id);
return car;
}
Nutzung
© 2012 TravelTainment
}
4.2.1.2 Vorteile der Technologie
Kein
Behandeln
von SQLExceptions
Kein
Ressourcenmanagement
Kapselung
JDBCCode in
Template
Anwendungslogik steht im Vordergrund
© 2012 TravelTainment
Kein
Iterieren
durch
ResultSet
© 2012 TravelTainment
Spring ORM
4.2.2 Spring ORM

Folgendes Kapitel konzentriert sich auf Hibernate

Spring bietet First-Level Support für Hibernate

Früher: Template-Klassen wie bei JDBC gesehen
Ziele
Einfaches
Testen und
Warten
Lose
Kopplung
© 2012 TravelTainment
Schichtentrennung
4.2.2.1 Nutzung von Hibernate mit Spring
Hibernate ohne Spring:


SessionFactory erzeugen mithilfe der Konfigurationsdatei
Hibernate mit Spring:

SessionFactory als Bean definieren

DataSource injizieren

SessionFactory in alle relevanten Klassen injizieren
<bean id="mySqlDataSource" class="...BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/table"/>
<property name="username" value="user_xy" />
<property name="password" value="pw_xy" />
</bean>
<bean id="sessionFactory" class="...LocalSessionFactoryBean">
<property name="dataSource" ref="mySqlDataSource" />
<property name="hibernateProperties">
<value>hibernate.dialect=...MySQLDialect</value>
<!--more hibernate properties-->
</property>
<!-- more sessionFactory properties -->
</bean>
© 2012 TravelTainment

SessionFactory in DAO nutzen
konsistente RuntimeExceptions
(DataAccessException).
Wie gewohnt, Hibernate
in DAOs benutzen
© 2012 TravelTainment
Injizieren der
SessionFactory-Bean
Annotieren mit
@Repository
4.2.2.1 Nutzung von Hibernate mit Spring
Weitere Erleichterung durch Spring-TransactionManagement:
Ohne Spring
• Manuelles Starten
und Beenden von
Transaktionen
Mit Spring
• @Transactional
• Spring handhabt
Transaktionen
eigenständig:
• Öffnen, Schließen,
Fehlerbehandlung
© 2012 TravelTainment

4.2.2.2 Vorteile

Einfache Möglichkeit, SessionFactorys bzw.
DataSources auszutauschen


Exceptions werden in einheitliche Hierarchie überführt
Transaktionsmanagement wird vereinfacht

Allgemein:
Dependency Injection
Losere Kopplung zwischen
Applikationskomponenten
© 2012 TravelTainment
Geschäftslogik wird von
Datenzugriffs- und
Transaktionsstrategien getrennt
© 2012 TravelTainment
Kapitel 5
Fazit
5. Fazit
Spring JDBC:

JdbcTemplate kapselt „boilerplate code“

Kein manuelles Verbindungs-, Transaktions- oder
Ressourcenmanagement notwendig

Spring vereinfacht Mapping zwischen Objekt und
relationalem Datensatz (RowMapper)

Weiterhin SQL-basiert
© 2012 TravelTainment

5. Fazit
Spring ORM/Hibernate:

Kein Template, sondern Arbeiten mit Standard-API

Kein manuelles Aufsuchen der Konfigurationsdatei oder
Erstellen der SessionFactory

Definition der SessionFactory in Spring-Context führt zu
loserer Kopplung

Transaktions- und Exceptionhandling wird verbessert

Spring ist eine Bereicherung für Hibernate-Anwendung!
© 2012 TravelTainment

Quellen






M. Konda, Just Spring Data Access, 2012
R. Johnson, J. Hoeller u.a., Spring Framework
Reference Documentation 3.2.3, 2013
S. Slavic, „community.jboss.org“, 2010
M. Inden, Der Weg zum Java-Profi, 2011
M. Fowler, „martinfowler.com“, 2004
Wikipedia, August 2013: „Java Database
Connectivity“, „Objektrelationale Abbildung“, „Java
Persistence API“, „Spring“, „Hibernate“
Für detaillierte Angaben vgl. Literaturverzeichnis im
Skript.
© 2012 TravelTainment

© 2012 TravelTainment
Fragen
© 2012 TravelTainment
Vielen Dank für die Aufmerksamkeit
Herunterladen