Slide 1

Slide 1 text

Bootiful database- centric applications with jOOQ
 Michael Simons @rotnroll666

Slide 2

Slide 2 text

@spring_io #springio17 ABOUT ME MICHAEL SIMONS • Lives and works in Aachen • Developer at ENERKO INFORMATIK • Leader of the Euregio JUG • Blogs about Java, Spring and software architecture on
 info.michael-simons.eu • Co-Autor arc(42) by example • @rotnroll666 on Twitter

Slide 3

Slide 3 text

Database centric applications for the energy market

Slide 4

Slide 4 text

Desktop GIS using Oracle Spatial

Slide 5

Slide 5 text

JAVA AND DATABASES Plain SQL, ORM or something in between?

Slide 6

Slide 6 text

@spring_io #springio17 EVERYONE HAS THEIR OWN PERSISTENCE FRAMEWORK ACTUALLY, A LOT… • JDBC • Springs JDBCTemplate • JPA • JPQL • Criteria query • jOOQ • many more Y U NOT GIVE ME THE RIGHT TOOL?

Slide 7

Slide 7 text

@spring_io #springio17 WELL…

Slide 8

Slide 8 text

Quelle: https://www.flickr.com/photos/133021668@N04/31403416393

Slide 9

Slide 9 text

Quelle: https://www.flickr.com/photos/potentialpast/5582667252

Slide 10

Slide 10 text

Quelle: https://en.wikipedia.org/wiki/Wolf_of_Ansbach

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

@spring_io #springio17 EXAMPLE:
 TRACKING MUSICAL HABITS (*) (*) Also timeseries…

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

@spring_io #springio17 THE SCHEMA

Slide 15

Slide 15 text

@spring_io #springio17 HOW DO YOU WANT IT? PLAIN SQL Select * from tracks where album = 'True Survivor';

Slide 16

Slide 16 text

@spring_io #springio17 HOW DO YOU WANT IT? PLAIN JPA @Entity @Table(name = "tracks") public class TrackEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Column private String album; public static void main(String...a) { final EntityManagerFactory factory = Persistence.createEntityManagerFactory("whatever"); final EntityManager entityManager = factory.createEntityManager(); List tracks = entityManager .createQuery("Select t from tracks where album = :album") .setParameter("album", "True Survivor") .getResultList(); } }

Slide 17

Slide 17 text

@spring_io #springio17 HOW DO YOU WANT IT? JPA + SPRING DATA public interface TrackRepository extends JpaRepository { public List findAllByAlbum(final String name); public static void main(String...a) { TrackRepository trackRepository; final List tracks = trackRepository .findAllByAlbum("True Survivor"); } }

Slide 18

Slide 18 text

@spring_io #springio17 I WROTE A STATEMENT AND YOU DON’T BELIEVE WHAT HAPPENED NEXT…

Slide 19

Slide 19 text

@spring_io #springio17 THE WINDOW FUNCTION…IT MOVES THROUGH EVERY LIVING THING SELECT ALL THE STUFF… WITH previous_month AS (SELECT p.track_id, count(*) as cnt, dense_rank() over(order by count(*) desc) as position FROM plays p WHERE trunc(p.played_on, 'DD') BETWEEN
 date'2016-04-01' and date'2016-04-30' GROUP BY p.track_id), current_month AS (SELECT p.track_id, count(*) as cnt, dense_rank() over(order by count(*) desc) as position FROM plays p WHERE trunc(p.played_on, 'DD') BETWEEN 
 date'2016-05-01' and date'2016-05-31' GROUP BY p.track_id) SELECT a.artist || ' - ' || t.name || ' (' || t.album || ')' as label, current_month.cnt, previous_month.position - current_month.position as change FROM tracks t JOIN artists a on a.id = t.artist_id JOIN current_month current_month on current_month.track_id = t.id LEFT OUTER join previous_month on previous_month.track_id = t.id ORDER BY current_month.cnt desc, label asc FETCH FIRST 20 ROWS ONLY;

Slide 20

Slide 20 text

@Entity @SqlResultSetMapping( name = "ChartMapping", columns = { @ColumnResult(name = "label", type = String.class), @ColumnResult(name = "cnt", type = Integer.class), @ColumnResult(name = "chage", type = Integer.class) }) @NamedNativeQueries( @NamedNativeQuery( name = "ChartQuery", resultSetMapping = "ChartMapping", query = "" + "WITH \n" + " previous_month AS\n" + " (SELECT p.track_id, count(*) as cnt, \n" + " dense_rank() over(order by count(*) desc) as position \n" + " FROM plays p \n" + " WHERE trunc(p.played_on, 'DD') between date'2016-04-01' and date'2016-04-30' GROUP BY p.track_id),\n" + " current_month AS\n" + " (SELECT p.track_id, count(*) as cnt, \n" + " dense_rank() over(order by count(*) desc) as position \n" + " FROM plays p \n" + " WHERE trunc(p.played_on, 'DD') between date'2016-05-01' and date'2016-05-31' GROUP BY p.track_id)\n" + "SELECT a.artist || ' - ' || t.name || ' (' || t.album || ')' as label,\n" + " current_month.cnt, \n" + " previous_month.position - current_month.position as change\n" + " FROM tracks t\n" + " JOIN artists a on a.id = t.artist_id\n" + " JOIN current_month current_month on current_month.track_id = t.id\n" + " LEFT OUTER join previous_month on previous_month.track_id = t.id\n" + " ORDER BY current_month.cnt desc, label asc" ) ) public class PlayEntity { public static void main(String... a) { // Don't do this at home EntityManager entityManager; List results = entityManager.createNamedQuery("ChartQuery").setMaxResults(20).getResultList(); results.stream().forEach((record) -> { String label = (String) record[0]; Integer cnt = (Integer) record[1]; Integer change = (Integer) record[2]; }); } } REALLY? SQL MEETS JAVA this.create .with(currentMonth) .with(previousMonth) .select(label, currentMonth.field("cnt"), previousMonth.field("position").minus( currentMonth.field("position") ).as("change") ) .from(TRACKS) .join(ARTISTS).onKey() .join(currentMonth) .on(currentMonth.field("track_id", BigDecimal.class) .eq(TRACKS.ID)) .leftOuterJoin(previousMonth) .on(previousMonth.field("track_id", BigDecimal.class) .eq(TRACKS.ID)) .orderBy(currentMonth.field("cnt").desc(), label.asc()) .limit(n) .fetch() .formatJSON(response.getOutputStream());

Slide 21

Slide 21 text

@spring_io #springio17 JUST BECAUSE YOU'RE USING HIBERNATE, DOESN'T MEAN YOU HAVE TO USE IT FOR EVERYTHING. Gavin King JPA & HIBERNATE?

Slide 22

Slide 22 text

@spring_io #springio17 JOOQ

Slide 23

Slide 23 text

@spring_io #springio17 JAVA OBJECT ORIENTED QUERYING WHAT IS JOOQ? • „Query builder framework“ • Java DSL for generating database and schema specific statements • The schema is the leading factor • jOOQ generates a corresponding Java-schema • Typesafe • OpenSource for OpenSource Datenbanken, $ ~ $$ for Enterprise databases

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

JOOQ JAVA-BASED SCHEMA BUILD 
 PROCESS runs GENERATOR DATABASE reverse
 engineers JAVA-BASED
 SCHEMA creates APPLICATION DSL CONTEXT uses uses SQL generates

Slide 26

Slide 26 text

@spring_io #springio17 SCHEMA DATABASE MIGRATIONS ARE ESSENTIAL • Liquibase • Flyway

Slide 27

Slide 27 text

@spring_io #springio17 DATABASEMIGRATIONS WORKFLOW

Slide 28

Slide 28 text

@spring_io #springio17 DATABASEMIGRATIONS WORKFLOW • Build against development database • starts migration • starts jOOQ generator

Slide 29

Slide 29 text

@spring_io #springio17 DATABASEMIGRATIONS WORKFLOW • Build against development database • starts migration • starts jOOQ generator • Application runs against production database • starts migration again ➡Generated Java schema is in sync with the production database

Slide 30

Slide 30 text

HOW TO USE THIS WITH SPRING BOOT? org.springframework.boot spring-boot-starter-jooq org.flywaydb flyway-core

Slide 31

Slide 31 text

org.springframework.boot spring-boot-starter-jooq org.jooq jooq org.jooq.pro jooq ${jooq.version} org.flywaydb flyway-core HOW TO USE THIS WITH SPRING BOOT?

Slide 32

Slide 32 text

@spring_io #springio17 jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 doag2016 doag2016 DOAG2016 DEVELOPMENT CONNECTION INSIDE POM THE BUILD PROCESS IS A LITTLE BIT „HARDER“ spring.datasource.url = @db.url@ spring.datasource.username = @db.username@ spring.datasource.password = @db.password@ USE MAVEN PROPERTIES IN DEFAULT CONFIGURATION

Slide 33

Slide 33 text

@spring_io #springio17 RUN FLYWAY DURING BUILD AND RUNTIME FLYWAY org.flywaydb flyway-maven-plugin ${flyway.version} generate-sources migrate ${db.url} ${db.username} ${db.password} filesystem:src/main/resources/db/migration

Slide 34

Slide 34 text

@spring_io #springio17 JOOQ AFTER MIGRATIONS JOOQ org.jooq.pro jooq-codegen-maven ${jooq.version} generate-sources generate oracle.jdbc.OracleDriver ${db.url} ${db.username} ${db.password}

Slide 35

Slide 35 text

@spring_io #springio17 DEMO

Slide 36

Slide 36 text

@spring_io #springio17 SUMMARY • Map queries to URLs • Simple as well as complex queries • Logging of generated queries is quite useful • Spring MVC parameters can be used without fear of SQL injection as bind parameters • Reuse query fragments • Mapping records to POJOs and other • DAOs possible, too • Use jOOQ as SQL generator only

Slide 37

Slide 37 text

@spring_io #springio17 IS THIS PORTABLE?

Slide 38

Slide 38 text

@spring_io #springio17 DEMO WAS CREATED ORACLE 12C… NOW ON POSTGRESQL MOSTLY… • jOOQ tries to be as close as possible to SQL-standards • knows how to emulate clauses for various databases • Example • LIMIT vs. OFFSET x ROWS / FETCH • Vendor specific functions (trunc vs. date_trunc etc.)

Slide 39

Slide 39 text

@spring_io #springio17 WHEN TO USE THIS?

Slide 40

Slide 40 text

@spring_io #springio17 THE SQL… IT'S ALWAYS BEEN THERE, IT WILL GUIDE YOU Lukas Skyeder THE PROBLEM WITH INTERNET QUOTES IS THAT YOU CANT ALWAYS DEPEND ON THEIR ACCURACY" - ABRAHAM LINCOLN, 1864

Slide 41

Slide 41 text

@spring_io #springio17 USECASES • Analytic functions (Use the database features you most likely paid for already) • „Upsert“ (Merge-Statements) • Partial selects (only the columns you need without going through Entity Graphs)

Slide 42

Slide 42 text

@spring_io #springio17 BACK TO SILVER BULLETS…

Slide 43

Slide 43 text

@spring_io #springio17 WHERE ARE THE SILVER BULLETS NOW? JPA / HIBERNATE *AND* JOOQ • Automatic database migrations • JPA / Hibernate with Spring Data JPA • JPQL Queries if necessary (Criteria queries if masochistic) • Don’t hide native queries in annotations! • Create complex queries and projections with jOOQ • Pass to EntityManager to retrive Entities or • use DSL Context directly

Slide 44

Slide 44 text

@spring_io #springio17 „GIVE ME THE GENRE THAT HAS BEEN PLAYED THE MOST…“ (*) (*) Classic SQL-Interview question

Slide 45

Slide 45 text

@spring_io #springio17 „AS A JPA-ENTITY!“

Slide 46

Slide 46 text

@spring_io #springio17 ALL ENTRIES THAT HAVE „THE MOST“ PLAIN SQL select id, genre from ( select g.id, g.genre, rank() over (order by count(*) desc) rnk from plays p join tracks t on p.track_id = t.id join genres g on t.genre_id = g.id group by g.id, g.genre ) src where src.rnk = 1;

Slide 47

Slide 47 text

@spring_io #springio17 PERFECTLY FINE TO USE INSIDE SPRING DATA JPA REPOSITORY 2 INTERFACES, ONE CLASS Custom extension GenreRepositoryExt interface containing interface GenreRepositoryExt { List findWithHighestPlaycount(); }

Slide 48

Slide 48 text

@spring_io #springio17 PERFECTLY FINE TO USE INSIDE SPRING DATA JPA REPOSITORY 2 INTERFACES, ONE CLASS Spring Data JPA Repository, extending GenreRepositoryExt
 public interface GenreRepository extends CrudRepository, GenreRepositoryExt { }

Slide 49

Slide 49 text

@spring_io #springio17 Class implementing our query with jOOQ class GenreRepositoryImpl implements GenreRepositoryExt { private final EntityManager entityManager; private final DSLContext create; public List findWithHighestPlaycount() { final SelectQuery sqlGenerator = this.create.select()./* Query */getQuery(); final String sql = sqlGenerator .getSQL(ParamType.NAMED); final Query query = entityManager .createNativeQuery(sql, GenreEntity.class); return query.getResultList(); } } PERFECTLY FINE TO USE INSIDE SPRING DATA JPA REPOSITORY 2 INTERFACES, ONE CLASS

Slide 50

Slide 50 text

@spring_io #springio17 DEMO

Slide 51

Slide 51 text

@spring_io #springio17 RESOURCES KNOW YOUR TOOLS! • Most certainly the manuals! • https://modern-sql.com • https://blog.jooq.org • https://vladmihalcea.com/tutorials/ hibernate/ • http://www.thoughts-on-java.org/ persistence/

Slide 52

Slide 52 text

@spring_io #springio17 RESOURCES THANK YOU FOR YOUR TIME! • Demo project:
 github.com/michael-simons/bootiful-databases • Slides:
 speakerdeck.com/michaelsimons • Kontakt: michael-simons.eu • Twitter: @rotnroll666

Slide 53

Slide 53 text

@spring_io #springio17 RESOURCES SPRING BOOT BUCH • Q4 2017 at Dpunkt.verlag • springbootbuch.de • @springbootbuch • Example for chapter „Persistenz“:
 github.com/springbootbuch/database_examples
 Contains JDBCTemplate, JPA and JOOQ with Pagila-Demo Database (PostgreSQL)