JDBC, JPA, Hibernate

Spring with JDBC

@Repository
class PersonJdbcDao {

    @Autowired
    JdbcTemplate template;
    
    public List<Person> findAll() {
        return template.query("select * from person", 
            new BeanPropertyRowMapper(Person.class));
    }
}

Spring with JPA EntityManager

@Transactional
@Repository
class SomeRepository {

    @Autowired
    EntityManager manager;
    
    public SomeClass findById(Long id) {
        return manager.find(SomeClass.class, id);
    }
    
    public void createAndUpdate(Course course) {
        manager.persist(course); // entity is stored in db
        course.setName("new name");
        // even though I do not ask explicitly to merge 
        // the entity in db => entity is updated
        // because the method is declared to be transactional
    }
    
    public void detachExample(Course course) {
        manager.persist(course);
        maanger.detach(course); 
        // entity is not tracked any more by manager
        // => following update is not happening
        course.setName("new name");
    }

    public void clearExample(Course course) {
        manager.persist(course);
        maanger.clear(); 
        // no entity is tracked by manager
        // => course is not updated
        course.setName("new name");
    }

    public void refreshExample(Course course) {
        manager.persist(course); // course has name "Bla"
        course.setName("new name");
        maanger.refresh(course);
        // refresh loads current representation of course
        // => course will have name "Bla" at this point
    }
}

Hibernate annotations

@Entity
class Course {

    @UpdateTimestamp
    private LocalDateTime lastUpdatedDate;
    
    @CreationTimestamp
    private LocalDateTime createdDate;    

}

Working with dates

java.sql.Date vs java.util.Date vs java.time.LocalDate

Named queries

@Entity
@NamedQuery(name="my_query", query="select c from course c")
class Course {

    void theMethod(){ 
        TypedQuery<Course> = 
            EntityManager.createNamedQuery(
                "my_query", 
                Course.class);   
    }
}
@Entity
@NamedQueries(value = {
    @NamedQuery(name="my_query", query="select c from course c"),
    @NamedQuery(.....)
})    
class Course {
}

Native queries

@Transactional
@Repository
class SomeRepository {

    @Autowired
    EntityManager manager;
 
    public void theMEthod() {
        manager.createNativeQuery(
            "select * from person",
            Person,class);
    }   
    
    // native queries are useful for massive update
}    
    

Transactional

comment

javax @Transactional

manage transaction over single DB

spring @Transactional

(isolation=...)

manages transactions over several DBs (if you call many DBs in one method)

Spring Data JPA

// you can quickly expose repo as REST using spring-data-rest
@RepositoryRestResource(path="...")
interface MyRepo extend JpaRepository<Course, Long> {

    // provided out of the box
    //Optional<Course> course = findById(Long id);
    // ...
    
    // custom queries
    List<Course> findByName(String name);
    List<Course> findByNameOrderByIdDesc(String name);
    int countByName(String name);
    
    @Query("Select c From Course c where name like 'bla'")
    List<Course> coursesWithBlaName();
}

public class MyUnitTest {

    @Test
    public void testSorting() {
        Sort sort = new Sort(Sort.Direction.DESC, "name");
        myRepo.findAll(sort);
    }

    @Test
    public void testPagination() {
        PageRequest pageRequest = PageRequest.of(0,3);                 
        Page<Course> firstPage = myRepo.findAll(pageRequest);
        
        Pageable secondPageable = firstPage.nextPageable();
        Page<Course> secondPage = myRepo.findAll(secondPageable);
    }
}

Project setup for Spring, Hibernate and Kotlin

Great article which describes how to setup Hibernate properties for Kotlin case

@MappedSuperclass
abstract class AbstractJpaPersistable<T : Serializable> {

    companion object {
        private val serialVersionUID = -5554308939380869754L
    }

    @Id
    @GeneratedValue
    private var id: T? = null

    fun getId(): T? {
        return id
    }

    @Version
    var version: Int? = null

    @Column(name = "created_at")
    @CreationTimestamp
    var createdAt: LocalDateTime? = null

    @Column(name = "updated_at")
    @UpdateTimestamp
    var updatedAt: LocalDateTime? = null

    override fun equals(other: Any?): Boolean {
        other ?: return false
        if (this === other) return true
        if (javaClass != ProxyUtils.getUserClass(other)) return false
        other as AbstractJpaPersistable<*>
        return if (null == this.getId()) false else this.getId() == other.getId()
    }

    override fun hashCode(): Int {
        return 31
    }

    override fun toString() = "Entity of type ${this.javaClass.name} with id: $id"
}
//build.gradle.kts
plugins {
...	
	kotlin("plugin.jpa") version "1.6.21"
}

dependencies {
    implementation("org.hibernate:hibernate-core:5.6.12.Final")

    implementation("org.jetbrains.kotlin:kotlin-noarg")
    implementation("org.jetbrains.kotlin:kotlin-allopen")
}

Last updated