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