Get Back in Control of Your SQL with jOOQ, at #Java2Days.
SQL is a powerful and highly expressive language for queries against relational databases. SQL is established, standardised and hardly challenged by alternative querying languages. Nonetheless, in the Java ecosystem, there had been few relevant steps forward since JDBC to better integrate SQL into Java. All attention was given to object-relational mapping and language abstractions on a higher level, such as OQL, HQL, JPQL, CriteriaQuery. In the mean time, these abstractions have become almost as complex as SQL itself, regardless of the headaches they're giving to DBAs who can no longer patch the generated SQL.
jOOQ is a dual-licensed Open Source product filling this gap. It implements SQL itself as an internal domain-specific language in Java, allowing for the typesafe construction and execution of SQL statements of arbitrary complexity. This includes nested selects, derived tables, joins, semi-joins, anti-joins, self-joins, aliasing, as well as many vendor-specific extensions such as stored procedures, arrays, user-defined types, recursive SQL, grouping sets, pivot tables, window functions and many other OLAP features. jOOQ also includes a source code generator allowing you to compile queries in modern IDEs such as Eclipse very efficiently.
jOOQ is a good choice in a Java application where SQL and the specific relational database are important. It is an alternative when JPA / Hibernate abstract too much, JDBC too little. It shows, how a modern domain-specific language can greatly increase developer productivity, internalising SQL into Java.
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Get Back in Control of Your SQL with jOOQ at #Java2Days
1. Get Back in Control of your SQL
SQL and Java could work
together so much better if
we only let them.
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
2. Intro
SQL and Java
About my motivation
SQL dominates database systems
SQL seems «low level» and «dusty»
SQL can do so much more
SQL should be «sexy» again
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
3. Intro
SQL and Java
jOOQ
JDBC
PreparedStatement stmt = connection.prepareStatement(
"SELECT text FROM products WHERE cust_id = ? AND value < ?");
stmt.setInt(1, custID);
stmt.setBigDecimal(2, BigDecimal.ZERO);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("TEXT"));
}
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
4. Intro
SQL and Java
JDBC – the naked truth
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
PreparedStatement stmt = connection.prepareStatement(
"SELECT p.text txt" +
(isAccount ? ", NVL(a.type, ?) " : "") +
"FROM products p " +
(isAccount ? " INNER JOIN accounts a USING (prod_id) " : "") +
" WHERE p.cust_id = ? AND p.value < ?" +
(isAccount ? " AND a.type LIKE '%" + type + "%'" : "");
stmt.setInt(1, defaultType);
stmt.setInt(2, custID);
stmt.setBigDecimal(3, BigDecimal.ZERO);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Clob clob = rs.getClob("TEXT");
System.out.println(clob.getSubString(1, (int) clob.length());
}
rs.close();
stmt.close();
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
5. Intro
SQL and Java
jOOQ
Examples
JDBC – the naked truth
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
PreparedStatement stmt = connection.prepareStatement(
//
"SELECT p.text txt" +
//
(isAccount ? ", NVL(a.type, ?) " : "") +
//
"FROM products p " +
// Syntax error when isAccount == false
(isAccount ? " INNER JOIN accounts a USING (prod_id) " : "") + //
" WHERE p.cust_id = ? AND p.value < ?" +
//
(isAccount ? " AND a.type LIKE '%" + type + "%'" : "");
// Syntax error and SQL injection possible
stmt.setInt(1, defaultType);
// Wrong bind index
stmt.setInt(2, custID);
//
stmt.setBigDecimal(3, BigDecimal.ZERO);
//
ResultSet rs = stmt.executeQuery();
//
while (rs.next()) {
Clob clob = rs.getClob("TEXT");
System.out.println(clob.getSubString(1, (int) clob.length());
}
//
// ojdbc6: clob.free() should be called
//
//
rs.close();
stmt.close();
// close() not really in finally block
//
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
6. Intro
SQL and Java
EJB 2.0 EntityBeans
public interface CustomerRequest extends EJBObject {
BigInteger getId();
String getText();
void setText(String text);
@Override
void remove();
}
public interface CustomerRequestHome extends EJBHome {
CustomerRequest create(BigInteger id);
CustomerRequest find(BigInteger id);
}
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
7. Intro
SQL and Java
EJB 2.0 – the naked truth
<weblogic-enterprise-bean>
<ejb-name>com.example.CustomerRequestHome</ejb-name>
<entity-descriptor>
<pool>
<max-beans-in-free-pool>100</max-beans-in-free-pool>
</pool>
<entity-cache>
<max-beans-in-cache>500</max-beans-in-cache>
<idle-timeout-seconds>10</idle-timeout-seconds>
<concurrency-strategy>Database</concurrency-strategy>
</entity-cache>
<persistence>
<delay-updates-until-end-of-tx>True</delay-updates-until-end-of-tx>
</persistence>
<entity-clustering>
<home-is-clusterable>False</home-is-clusterable>
<home-load-algorithm>round-robin</home-load-algorithm>
</entity-clustering>
</entity-descriptor>
<transaction-descriptor/>
<enable-call-by-reference>True</enable-call-by-reference>
<jndi-name>com.example.CustomerRequestHome</jndi-name>
</weblogic-enterprise-bean>
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
8. Intro
SQL and Java
Hibernate – ORM
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(new Event("Conference", new Date());
session.save(new Event("After Party", new Date());
List result = session.createQuery("from Event").list();
for (Event event : (List<Event>) result) {
System.out.println("Event : " + event.getTitle());
}
session.getTransaction().commit();
session.close();
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
9. Intro
SQL and Java
Hibernate – «navigation»
List result = session.createQuery("from Event").list();
for (Event event : (List<Event>) result) {
System.out.println("Participants of " + event);
for (Person person : event.getParticipants()) {
Company company = person.getCompany();
System.out.println(person + " (" + company + ")");
}
}
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
jOOQ
Examples
10. Intro
SQL and Java
jOOQ
Hibernate – the naked truth
<hibernate-mapping package="org.hibernate.tutorial.hbm">
<class name="Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="increment"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
<set name="participants" inverse="true">
<key column="eventId"/>
<one-to-many entity-name="Person"/>
</set>
</class>
</hibernate-mapping>
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
11. Intro
SQL and Java
jOOQ
JPA and EJB 3.0
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
em.persist(new Event("Conference", new Date());
em.persist(new Event("After Party", new Date());
List result = em.createQuery("from Event").getResultList();
for (Event event : (List<Event>) result) {
System.out.println("Event : " + event.getTitle());
}
em.getTransaction().commit();
em.close();
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
12. Intro
SQL and Java
jOOQ
EJB 3.0 – the naked truth
@Entity @Table(name = "EVENTS")
public class Event {
private Long id;
private String title;
private Date date;
@Id @GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
public Long getId() { /* … */ }
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() { /* … */ }
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
13. Intro
SQL and Java
jOOQ
Examples
EJB 3.0 – Annotatiomania™
@OneToMany(mappedBy = "destCustomerId")
@ManyToMany
@Fetch(FetchMode.SUBSELECT)
@JoinTable(
name = "customer_dealer_map",
joinColumns = {
@JoinColumn(name = "customer_id", referencedColumnName = "id")
},
inverseJoinColumns = {
@JoinColumn(name = "dealer_id", referencedColumnName = "id")
}
)
private Collection dealers;
Found at http://stackoverflow.com/q/17491912/521799
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
14. Intro
SQL and Java
jOOQ
Examples
JPA 3.0 Preview – Annotatiomania™
@OneToMany @OneToManyMore @AnyOne @AnyBody
@ManyToMany @Many
@Fetch @FetchMany @FetchWithDiscriminator(name = "no_name")
@JoinTable(joinColumns = {
@JoinColumn(name = "customer_id", referencedColumnName = "id")
})
@PrefetchJoinWithDiscriminator
@IfJoiningAvoidHashJoins @ButUseHashJoinsWhenMoreThan(records = 1000)
@XmlDataTransformable @SpringPrefechAdapter
private Collection employees;
Might not be true
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
15. Intro
SQL and Java
jOOQ
Examples
Criteria – the naked truth
EntityManager em= ...
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> person = criteria.from(Person.class);
Predicate condition = builder.gt(person.get(Person_.age), 20);
criteria.where(condition);
TypedQuery<Person> query = em.createQuery(query);
List<Person> result = query.getResultList();
Found at http://docs.oracle.com/javaee/6/tutorial/doc/gjrij.html
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
17. Intro
SQL and Java
jOOQ
NoSQL?
Seen at the O’Reilly Strata Conf:
History of NoSQL by Mark Madsen. Picture published by Edd Dumbill
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
18. Intro
SQL and Java
jOOQ
Examples
SQL is so much more
|
TEXT | VOTES |
RANK | PERCENT |
|-------------|-------|------------|---------|
|
Hibernate | 1383 |
1 |
32 % |
|
jOOQ | 1029 |
2 |
23 % |
| EclipseLink |
881 |
3 |
20 % |
|
JDBC |
533 |
4 |
12 % |
| Spring JDBC |
451 |
5 |
10 % |
Data may not be accurate…
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
19. Intro
SQL and Java
jOOQ
SQL is so much more
SELECT
p.text,
p.votes,
DENSE_RANK() OVER (ORDER BY p.votes DESC) AS "rank",
LPAD(
(p.votes * 100 / SUM(p.votes) OVER ()) || ' %',
4, ' '
) AS "percent"
FROM
poll_options p
WHERE
p.poll_id = 12
ORDER BY p.votes DESC
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
20. Intro
SQL and Java
jOOQ
The same with jOOQ
select (p.TEXT,
p.VOTES,
denseRank().over().orderBy(p.VOTES.desc()).as("rank"),
lpad(
p.VOTES.mul(100).div(sum(p.VOTES).over()).concat(" %"),
4, " "
).as("percent"))
.from
(POLL_OPTIONS.as("p"))
.where (p.POLL_ID.eq(12))
.orderBy(p.VOTES.desc());
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples
21. Intro
SQL and Java
jOOQ
The same with jOOQ in Scala (!)
select (p.TEXT,
p.VOTES,
denseRank() over() orderBy(p.VOTES desc) as "rank",
lpad(
(p.VOTES * 100) / (sum(p.VOTES) over()) || " %",
4, " "
) as "percent")
from
(POLL_OPTIONS as "p")
where
(p.POLL_ID === 12)
orderBy (p.VOTES desc)
Copyright (c) 2009-2013 by Data Geekery GmbH. Slides licensed under CC BY SA 3.0
Examples