Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hibernate since 2001. Is time for Cyberpunk 2020?

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →
Avatar for hexmind hexmind
October 10, 2016

Hibernate since 2001. Is time for Cyberpunk 2020?

Hibernate was started in 2001 as an alternative to using EJB2-style entity beans. But today EJB is forgotten and everybody wants to make modern software with Java 8 features. Hibernate is de facto industry standard. But what if it isn’t universal solution for all systems? How to do better declarative or functional querying?

Let’s put aside classic Object-Relational Mapping and look at other, modern capabilities to know pros and cons of DSLs, lambdas and streams usage with relational databases.

Avatar for hexmind

hexmind

October 10, 2016

More Decks by hexmind

Other Decks in Programming

Transcript

  1. JDBC Connection dbConnection = null; PreparedStatement preparedStatement = null; String

    sql = "SELECT USER_ID, USERNAME FROM DBUSER WHERE USER_ID = ?"; // more SQL here List<User> result = new LinkedList<User> (); try { dbConnection = getDBConnection(); preparedStatement = dbConnection.prepareStatement(sql); preparedStatement.setInt(1, userId); // more parameters here ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { result.add(new User( rs.getLong("USER_ID"), rs.getString("USERNAME") // more columns here )); } return result; } catch (SQLException e) { throw new IllegalStateException(e); } finally { if (preparedStatement != null) { preparedStatement.close(); } if (dbConnection != null) { dbConnection.close(); } }
  2. JDBC IN JAVA 7/8 String sql = "select actor_id, concat(first_name,

    ' ', last_name) as fullname from sakila.actor where lcase(first_name) like lcase(?)"; // more SQL here List <ActorFullName> result = new LinkedList<> (); try (Connection c = dataSource.getConnection()) { try (PreparedStatement stmt = c.prepareStatement(sql)) { stmt.setString(1, "%" + text + "%"); // more parameters here try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) { result.add(new ActorFullName( rs.getLong("actor_id"), rs.getString("fullname") // more columns here )); } return result; } } } catch (SQLException e) { throw new IllegalStateException(e); } // try-with-resources close all
  3. SPRING JDBC TEMPLATE + GROOVY String sql = """ select

    actor_id, concat(first_name, ' ', last_name) as fullname from sakila.actor where lcase(first_name) like lcase(?) """ // more SQL here return jdbcTemplate.query(sql, ["%Karl%"] as Object[], // more parameters here { ResultSet rs, int rowNum -> new ActorFullName( rs.getLong("actor_id"), rs.getString("fullname") ) // more columns here } as RowMapper)
  4. 2001: A HIBERNATE ODYSSEY 2001 v0.8 alternative for EJB2-style 2003

    v2 HQL, criteria 2006 v3.2 JPA 1.0 2010 v3.5 JPA 2.0, typed criteria 2013 v4.3.0 JPA 2.1 2014 Java 8 2015 v5 hibernate with Java 8 support
  5. HIBERNATE AND JAVA 8 Java time (hibernate-java8) merged into core

    Optional<Book> book = session.byId(Book.class).loadOptional(id); Stream<Book> books = session.createQuery( "SELECT b FROM Book b", Book.class).stream();
  6. ANNOTATIONS? @Entity @Table(name = "CONTACTS") @NamedQueries({ @NamedQuery(name = "@HQL_GET_ALL_CONTACT", query

    = "from Contact") }) @NamedNativeQueries({ @NamedNativeQuery(name = "@SQL_GET_ALL_CONTACT", query = "select emp_id, contact_line1, city, zip from Contacts") }) public class Contact { @Id @Column(name = "emp_id", unique = true, nullable = false) @GeneratedValue(generator = "gen") @GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") }) private long id; @OneToMany(cascade = CascadeType.ALL) @JoinTable(name = "CONTACT_PHONE", joinColumns = { @JoinColumn(name = "CONTACT_ID") }, inverseJoinColumns = { @JoinColumn(name = "PHONE_ID") }) public Set<Phone> getContactPhoneNumbers() { return this.contactPhoneNumbers; } /* … */ }
  7. STRING-DRIVEN DEVELOPMENT @NamedNativeQuery(name = "nativeSQL", query = "SELECT emp1.emp_id, emp1.name,

    emp1.manager_id," + " emp1.dept_id, emp1.address_id" + " FROM EMP emp1, EMP emp2" + " WHERE ((emp2.EMP_ID = ?) AND (emp2.EMP_ID = emp1.MANAGER_ID))", resultClass = Professor.class)
  8. TYPESAFE CRITERIA CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<String> criteria = builder.createQuery(String.class);

    Root<Person> root = criteria.from(Person.class); criteria.select(root.get(Person_.nickName)); criteria.where(builder.equal(root.get(Person_.name), "John Doe")); List<String> names = entityManager.createQuery(criteria).getResultList();
  9. MYBATIS new SQL().INSERT_INTO("PERSON") .VALUES("ID, FIRST_NAME", "#{id}, #{firstName}"); new SQL() {

    SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME"); SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON"); FROM("PERSON P"); FROM("ACCOUNT A"); INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID"); INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID"); WHERE("P.ID = A.ID"); WHERE("P.FIRST_NAME like ?"); OR(); WHERE("P.LAST_NAME like ?"); GROUP_BY("P.ID"); HAVING("P.LAST_NAME like ?"); };
  10. QUERIES FROM METHOD NAMES extends Repository<T, ID> extends CrudRepository<T, ID>

    User findOneByDeletedIsFalseAndLogin(String login); User findOneByDeletedIsFalseAndEmail(String email); User findOneByDeletedIsFalseAndActivationKey(String key); List<Todo> findByDescriptionContainsOrTitleContainsAllIgnoreCase( String descriptionPart, String titlePart); List<InstanceConfig> findByConfigAppIdAndConfigClusterNameAndConfigNamespaceNameAn dDataChangeLastModifiedTimeAfter( String appId, String clusterName, String namespaceName, Date validDate);
  11. SPECIFICATIONS List<Customer> customers = customerRepository.findAll( where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount))); public class CustomerSpecs {

    public static Specification<Customer> isLongTermCustomer() { return (root, query, builder) -> { LocalDate date = LocalDate.now().minusYears(2); return builder.lessThan(root.get(_Customer.createdAt), date); }; } public static Specification<Customer> hasSalesOfMoreThan(BigDecimal amount) { return (root, query, builder) -> { return builder.greaterThan((root.get(_Customer.sales), amount); }; } // more specifications here }
  12. .NET LINQ Language Integrated Query Northwnd nw = new Northwnd(@"northwnd.mdf");

    var companyNameQuery = from cust in nw.Customers where cust.City == "London" select cust.CompanyName;
  13. RUBY ON RAILS Active Records users = User .where(name: 'David',

    occupation: 'Code Artist') .order(created_at: :desc)
  14. SCALA SLICK for { c <- coffees if c.price >

    9.0 s <- c.supplier } yield (c.name, s.name)
  15. JINQ 1.0 2014 Java 8 streams.streamAll(em, City.class) .filter(c -> c.getPopulation()

    > 25_000_000) .map(c -> c.getName()) .collect(toList()); streams.streamAll(em, City.class) .where(c -> c.getPopulation() > 25_000_000) .select(c -> c.getName()) .toList(); SELECT C.Name FROM City C WHERE C.Population > 25000000
  16. String equals(), compareTo() BigDecimal, BigInteger, Integer, int, Double, double, Long,

    long ==, <, <=, >, >=, !=, +, -, *, / Float, float ==, <, <=, >, >=, !=, +, -, *, / Boolean, boolean !, &&, ||, == byte[] java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar equals(), before(), after() enums ==, != entities ==, != java.util.Collection contains(), JPQL.isIn() AttributeConverter types equals(), ==, !=
  17. ORDERING AND GROUPING NumberPath<Long> count = Expressions.numberPath(Long.class, "c"); List<Tuple> userTitles

    = queryFactory .select(blogPost.title, blogPost.id.count().as(count)) .from(blogPost) .groupBy(blogPost.title) .orderBy(count.desc()) .fetch();
  18. RESULT HANDLING entities, collections, Groups non generic typesafe tuples constructor/accesors/fields

    projections Tuple result = query.select(actor.firstName, actor.lastName).from(actor).fetchOne(); String lastName = row.get(1, String.class); String firstName = row.get(actor.firstName);
  19. JPA 2 CRITERIA CriteriaQuery query = builder.createQuery(); Root<Person> men =

    query.from(Person.class); Root<Person> women = query.from(Person.class); Predicate menRestriction = builder.and( builder.equal(men.get(Person_.gender), Gender.MALE), builder.equal(men.get(Person_.relationshipStatus), RelationshipStatus.SINGLE)); Predicate womenRestriction = builder.and( builder.equal(women.get(Person_.gender), Gender.FEMALE), builder.equal(women.get(Person_.relationshipStatus), RelationshipStatus.SINGLE)); query.where(builder.and(menRestriction, womenRestriction));
  20. QUERYDSL JPAQuery query = new JPAQuery(em); QPerson men = new

    QPerson("men"); QPerson women = new QPerson("women"); query.from(men, women).where( men.gender.eq(Gender.MALE), men.relationshipStatus.eq(RelationshipStatus.SINGLE), women.gender.eq(Gender.FEMALE), women.relationshipStatus.eq(RelationshipStatus.SINGLE));
  21. SPRING DATA WITH QUERYDSL extends QueryDslPredicateExecutor long count(Predicate predicate); boolean

    exists(Predicate predicate); Iterable<T> findAll(Predicate predicate); T findOne(Predicate predicate); QTodo todo = QTodo.todo; repository.findAll(todo.group.eq(group) .and(todo.done.eq(false)));
  22. ARTEFACTS schema metamodel (active) records POJOs, immutable POJOs, fluent setters

    JPA annotations, validation annotations DAOs, Spring annotations stored procedures
  23. RECORDS strongly typed weakly typed BookRecord book = create.selectFrom(BOOK).fetchOne(); String

    title = book.getTitle()); Record record = create.select().from(BOOK) .join(AUTHOR).on(BOOK.AUTHOR_ID).fetchOne(); BookRecord book = record.into(BOOK); AuthorRecord author = record.into(AUTHOR);
  24. WHEN DATABASE FIRST data driven system more relational than hierarchical

    data model several applications access the same database
  25. WHEN TYPESAFE QUERIES more complex querying than CRUD Command Query

    Responsibility Segregation SQL code in Java code
  26. OR AS CYBERWARE as a SQL executor as a SQL

    builder as Active Records as CRUD with Hibernate, Spring Data...
  27. ★ POPULARITY 392 jinq 583 speedment 990 querydsl 1354 jooq

    2051 hibernate-orm stars on Github before 10.10.2016