SlideShare a Scribd company logo
Alternatives to JPA
NaverTech talk
debop@coupang.com 2019.01.22
Alternatives to JPA
Agenda
• What is ORM
• Pros / Cons of JPA
• Current status in Coupang
• Alternatives of JPA
• Slick
• jOOQ
• Exposed
• Requery
ORM (Object Relational Mapping)
• OOP’s object graph vs Relational Database
• Focus OOP, not Relational Database
• No matter of RDBMS vendor - Same code
• Hibernate coverage is 95% over traditional SQL statements
• ORM not suitable for data centric application in performance
• Why should you use an ORM?
Pros of JPA
• Focus to Java Object graph & OOP
• No need to know relations and constraints of entities
• No need to know specific DB features by various vendor
• No need to know SQL, just use Java API
• Supplement by HQL or JPQL or QueryDSL
• All support for Stateful, Stateless (Default is Stateful)
Cons of JPA
• If you knew SQL already, JPA is wired
• Hard to learning (exponential)
• Low performance by stateful and fetch by id
• No suitable for Bulk or Set operations
• Massive Insert, Statistical Summary (Cube …)
• Non-Threadsafe Session - Low throughput
• Need to learn specific JPAVendor (Hibernate, Eclipse Link)
• HQL, @DynamicInsert, @LazyCollection
• 2nd Cache (recommend JCache (JSR-305))
Current Status in Coupang
• No Deep Dive
• Missing override (hashCode, equals, toString)
• No using @NatualId
• Bad Policy / Bad Design
• Every entity has Own identifier (Some case no need)
• Poor performance -> Mislead “JPA is bad”
• Apply not suitable case
• Bulk operations, Statistical operations
• No use supplement features
• StatelessSession, 2nd Cache …
DB: H2 Memory DB, CPU Core: 12, OS: Linux Mint, JVM: Java 8
0
5,000
10,000
15,000
20,000
25,000
30,000
35,000
40,000
45,000
50,000
10 1000 5000
JPA vs Requery Insert Benchmark
JPA Requery
Features in Alternatives of JPA
• Design Principle
• OOP based, Support Multi DBVendor
• No need stateful for Reference object
• Support association, inheritance, converter in JPA
• Performance
• Speed up to Plain SQL
• Stateless
• Support Asynchronous or Reactive
• Support Bulk or Batch operations
Slick
ORM for Scala
Slick
• Database access library
• Not ORM -> Functional Relational Mapping
• Bring relational model to Scala OOP
• Natural fit ( no impedance mismatch)
• Stateless
• Matures (Slick version 3) (Non-blocking DBIO)
• Essential Slick Book
Slick - schema definition
Entity
Schema
Definition
Slick - Query
// Get Users with age > 20
Query statement
Async
Operations
Slick - DML
Slick -Transactions
Define Repository
Async
Execution with
Transaction
Slick - Plain SQL
ResultSet to
Tuple
ResultSet to
Entity
jOOQ
Java Object Oriented Query
jOOQ
• Reflect Database Schema to generate Entity Class
• Typesfe SQL (akaTypesafe MyBatis)
• Database First (Not ORM)
• Stateless
• Need DBMS Owner Authority
• jOOQ vs Hibernate :When to choose which
jOOQ - typesafe SQL
SELECT * FROM BOOK
WHERE BOOK.PUBLISHED_IN = 2011
ORDER BY BOOK.TITLE
create.selectFrom(BOOK)
.where(BOOK.PUBLISHED_IN.eq(2011))
.orderBy(BOOK.TITLE)
select().from(t).where(t.a.eq(select(t2.x).from(t2));
// Type-check here: ---------------> ^^^^
select().from(t).where(t.a.eq(any(select(t2.x).from(t2)));
// Type-check here: -------------------> ^^^^
select().from(t).where(t.a.in(select(t2.x).from(t2));
// Type-check here: ---------------> ^^^^
select(t1.a).from(t1).unionAll(select(t2.a).from(t2));
// Type-check here: ----------------> ^^^^
select(t1.a, t1.b).from(t1).union(select(t2.a, t2.b).from(t2));
// Type-check here: -------------------> ^^^^^^^^^^
Predicates
Set operations
requery
ORM for Java & Kotlin & Android
requery
• No reflection (apt code generation) - Fast instancing
• Fast startup & performance
• Schema generation
• Blocking / Non-blocking API (Reactive with RxJava)
• Support partial object / refresh / upsert
• Custom type converter like JPA
• Compile time entity validation
• Support almost JPA annotations
@Entity
abstract class AbstractPerson { 
    @Key @Generated int id; 
   
    @Index("name_index") // table specification 
    String name;     
   
    @OneToMany // relationships 1:1, 1:many, many to many   
    Set<Phone> phoneNumbers;
   
    @Converter(EmailToStringConverter.class)
    Email email;
    @PostLoad // lifecycle callbacks
    void afterLoad() { updatePeopleList(); }
    // getter, setters, equals & hashCode automatically generated into Person.java 
}
requery - define entity
Identifier
Entity class
Converter
Listeners
Result<Person> query = data
    .select(Person.class)
    .where(Person.NAME.lower().like("b%"))
    .and(Person.AGE.gt(20))
    .orderBy(Person.AGE.desc())
    .limit(5)
    .get();
Observable<Person> observable = data
    .select(Person.class)
    .orderBy(Person.AGE.desc())
    .get()
    .observable();
requery - query
Query by Fluent API
Reactive Programming
Cold Observable
Non blocking
@Entity(model = "tree")

interface TreeNode {

    @get:Key

    @get:Generated

    val id: Long
   
    @get:Column

    var name: String



    @get:ManyToOne(cascade = [DELETE])
    var parent: TreeNode?



    @get:OneToMany(mappedBy = "parent", cascade = [SAVE, DELETE])

    val children: MutableSet<TreeNode>
}
requery - self refence by Kotlin
Identifier
Entity class
1:N, N:1
Cascade
requery - Blob/Clob usage
class ByteArrayBlobConverter : Converter<ByteArray, Blob> {
override fun getPersistedSize(): Int? = null
override fun getPersistedType(): Class<Blob> = Blob::class.java
override fun getMappedType(): Class<ByteArray> = ByteArray::class.java
override fun convertToMapped(type: Class<out ByteArray>?, value: Blob?): ByteArray? {
return value?.binaryStream?.readBytes()
}
override fun convertToPersisted(value: ByteArray?): Blob? {
return value?.let { SerialBlob(it) }
}
}
requery - Blob property
@Entity(model = "kt")
interface BigModel {
@get:Key
@get:Generated
@get:Column(name = "model_id")
val id: Int
@get:Column(name = "model_name")
var name: String?
@get:Convert(value = ByteArrayBlobConverter::class)
@get:Column(name = "model_picture")
var picture: ByteArray?
}
Blob column
Exposed
Kotlin SQL Framework
Exposed - Kotlin SQL Framework
• Lightweight SQL Library
• Provide two layers of data access
• Typesafe SQL wrapping DSL
• Lightweight Data Access Object
• See : First steps with Kotlin/Exposed
• Cons
• Not mature
Exposed - SQL DSL
object Users : Table() {
    val id = varchar("id", 10).primaryKey() // Column<String> 
    val name = varchar("name", length = 50) // Column<String>
    val cityId = (integer("city_id") references Cities.id).nullable() // Column<Int?>
}
object Cities : Table() { 
    val id = integer("id").autoIncrement().primaryKey() // Column<Int>
    val name = varchar("name", 50) // Column<String> 
}
Exposed - SQL DSL
val munichId = Cities.insert {
    it[name] = "Munich"
} get Cities.id 
Cities.insert { it[name] = "Prague" } 
Users.insert { 
    it[id] = "andrey" 
    it[name] = "Andrey" 
    it[cityId] = saintPetersburgId 
}
Users.insert { 
    it[id] = "sergey"
    it[name] = "Sergey" 
    it[cityId] = munichId
}
Exposed - SQL DSL - Join
(Users innerJoin Cities)
    .slice(Users.name, Cities.name)
    .select {
        (Users.id.eq("andrey") or Users.name.eq("Sergey")) and
        Users.id.eq("sergey") and Users.cityId.eq(Cities.id)
    }
    .forEach { 
        println("${it[Users.name]} lives in ${it[Cities.name]}")
    }
Exposed - SQL DSL - Join 2
((Cities innerJoin Users)
    .slice(Cities.name, Users.id.count())
    .selectAll()
    .groupBy(Cities.name))
    .forEach {
        val cityName = it[Cities.name]
        val userCount = it[Users.id.count()]
        if (userCount > 0) {
            println("$userCount user(s) live(s) in $cityName")
        } else { 
            println("Nobody lives in $cityName")
        }
     }
Exposed - DAO
object Users : IntIdTable() {
    val name = varchar("name", 50).index()
    val city = reference("city", Cities)
    val age = integer("age")
}
object Cities: IntIdTable() { 
    val name = varchar("name", 50)
}
Schema Definition
class User(id: EntityID<Int>) : IntEntity(id){
    companion object : IntEntityClass<User>(Users)
    var name by Users.name
    var city by City referencedOn Users.city
    var age by Users.age 
}
class City(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<City>(Cities)
    var name by Cities.name
    val users by User referrersOn Users.city 
}
Entity Definition
Exposed - DAO Usage
val munich = City.new {
    name = "Munich"
}
User.new {
    name = "a"
    city = munich
    age = 5
}
User.new {
    name = "b"
    city = munich
    age = 27
}
munich.users.joinToString { it.name }
User.find { Users.age.between(18, 60) }
OneTo Many
All user’s name in Munich
Conclusion
• Already legacy database exists ? Use only Java
• jOOQ or requery
• Scala only ? -> Slick
• Kotlin only ? -> requery, Exposed
• No matter language? -> requery
• Need Reactive programming? ->
• requery with kotlinx-requery
• kotlinx-rxjava2-jdbc ( we will open March )
Requery
Agenda
• Requery Overview 

• Why Requery

• Define Mapping

• Usage EntityDataStore

• EntityDataStore for Kotlin (Coroutines)

• Introduction of Spring Data Requery
Requery Overview
• ORM Library for Java, Kotlin, Android

• No Reflection (vs Hibernate proxy)

• Typed Query language (vs Hibernate Criteria)

• Upsert/Partial objects refresh

• Compile time entity/query validation (vs Hibernate)

• Entity is stateless (vs Hibernate stateful)

• Thread 에 제한 받지 않음 (vs JPA EntityManager)

• Support RxJava, Async Operations, Java 8
Why Requery
• Provide benefit of ORM

• Entity Mapping

• Schema Generation

• Compile time error detecting

• Performance 

• When bulk job, max 100x than JPA

• REST API - 2~10x throughput

• Support Upsert, Lazy loading …
DB: H2 Memory DB, CPU Core: 12, OS: Linux Mint, JVM: Java 8
0
5,000
10,000
15,000
20,000
25,000
30,000
35,000
40,000
45,000
50,000
10 1000 5000
JPA vs Requery Insert Benchmark
JPA Requery
Define Entity - Java
@Getter
@Entity(name = "BasicUser", copyable = true)
@Table(name = "basic_user")
public abstract class AbstractBasicUser extends AuditableLongEntity {
@Key
@Generated
protected Long id;
protected String name;
protected String email;
protected LocalDate birthday;
protected Integer age;
@ForeignKey
@OneToOne
protected AbstractBasicLocation address;
@ManyToMany(mappedBy = "members")
protected Set<AbstractBasicGroup> groups;
@Column(unique = true)
protected UUID uuid;
Define Entity - Kotlin
@Entity(model = "functional")
interface Person: Persistable {
@get:Key
@get:Generated
val id: Long
@get:Index(value = ["idx_person_name_email"])
var name: String
@get:Index(value = ["idx_person_name_email", "idx_person_email"])
var email: String
var birthday: LocalDate
@get:Column(value = "'empty'")
var description: String?
@get:Nullable
var age: Int?
@get:ForeignKey
@get:OneToOne(mappedBy = "person", cascade = [CascadeAction.DELETE, CascadeAction.SAVE])
var address: Address?
@get:OneToMany(mappedBy = "owner", cascade = [CascadeAction.DELETE, CascadeAction.SAVE])
val phoneNumbers: MutableSet<Phone>
@get:OneToMany
val phoneNumberList: MutableList<Phone>
@get:ManyToMany(mappedBy = "members")
val groups: MutableResult<Group>
@get:ManyToMany(mappedBy = "owners")
val ownedGroups: MutableResult<Group>
@get:ManyToMany(mappedBy = "id")
@get:JunctionTable
val friends: MutableSet<Person>
@get:Lazy
var about: String?
@get:Column(unique = true)
var uuid: UUID
var homepage: URL
var picture: String
}
EntityDataStore<Object>
• findByKey

• select / insert / update / upsert / delete 

• where / eq, lte, lt, gt, gte, like, in, not …

• groupBy / having / limit / offset

• support SQL Functions

• count, sum, avg, upper, lower …

• raw query
@Test
fun `insert user`() {
val user = RandomData.randomUser()
withDb(Models.DEFAULT) {
insert(user)
assertThat(user.id).isGreaterThan(0)
val loaded = select(User::class) where (User::id eq user.id) limit 10
assertThat(loaded.get().first()).isEqualTo(user)
}
}
val result = select(Location::class)
.join(User::class).on(User::location eq Location::id)
.where(User::id eq user.id)
.orderBy(Location::city.desc())
.get()
val result = raw(User::class, "SELECT * FROM Users")
val rowCount = update(UserEntity::class)
.set(UserEntity.ABOUT, "nothing")
.set(UserEntity.AGE, 50)
.where(UserEntity.AGE eq 100)
.get()
.value()
val count = insert(PersonEntity::class, PersonEntity.NAME, PersonEntity.DESCRIPTION)
.query(select(GroupEntity.NAME, GroupEntity.DESCRIPTION))
.get()
.first()
.count()
CoroutineEntityDataStore
val store = CoroutineEntityStore(this)
runBlocking {
val users = store.insert(RandomData.randomUsers(10))
users.await().forEach { user ->
assertThat(user.id).isGreaterThan(0)
}
store
.count(UserEntity::class)
.get()
.toDeferred()
.await()
.let {
assertThat(it).isEqualTo(10)
}
}
with(coroutineTemplate) {
val user = randomUser()
// can replace with `withContext { }`
async { insert(user) }.await()
assertThat(user.id).isNotNull()
val group = RandomData.randomGroup()
group.members.add(user)
async { insert(group) }.await()
assertThat(user.groups).hasSize(1)
assertThat(group.members).hasSize(1)
}
spring-data-requery
• RequeryOperations

• Wrap EntityDataStore

• RequeryTransactionManager for TransactionManager

• Support Spring @Transactional

• Better performance than spring-data-jpa

• when exists, paging, not load all entities
spring-data-requery
• Repository built in SQL

• ByPropertyName Auto generation methods

• @Query for Native SQL Query

• Query By Example

• Not Supported

• Association Path (not specified join method)

• Named parameter in @Query (just use `?`)
(support next version)
Setup spring-data-requery
@Configuration
@EnableTransactionManagement
public class RequeryTestConfiguration extends AbstractRequeryConfiguration {
@Override
@Bean
public EntityModel getEntityModel() {
return Models.DEFAULT;
}
@Override
public TableCreationMode getTableCreationMode() {
return TableCreationMode.CREATE_NOT_EXISTS;
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
Provided Beans
@Bean
public io.requery.sql.Configuration requeryConfiguration() {
return new ConfigurationBuilder(dataSource, getEntityModel())
// .useDefaultLogging()
.setEntityCache(new EmptyEntityCache())
.setStatementCacheSize(1024)
.setBatchUpdateSize(100)
.addStatementListener(new LogbackListener())
.build();
}
@Bean
public EntityDataStore<Object> entityDataStore() {
log.info("Create EntityDataStore instance.");
return new EntityDataStore<>(requeryConfiguration());
}
@Bean
public RequeryOperations requeryOperations() {
log.info("Create RequeryTemplate instance.");
return new RequeryTemplate(entityDataStore(), requeryMappingContext());
}
EntityCache 설정Tip :
개발 시에는 EmptyEntityCache,
운영 시에는 Cache2kEntityCache 사용
Use @Query in Repository
interface DeclaredQueryRepository extends RequeryRepository<BasicUser, Long> {
@Query("select * from basic_user u where u.email = ?")
BasicUser findByAnnotatedQuery(String email);
@Query("select * from basic_user u where u.email like ?")
List<BasicUser> findAllByEmailMatches(String email);
@Query("select * from basic_user u limit ?")
List<BasicUser> findWithLimits(int limit);
@Query("select * from basic_user u where u.name=? and u.email=? limit 1")
BasicUser findAllBy(String name, String email);
@Query("select u.id, u.name from basic_user u where u.email=?")
List<Tuple> findAllIds(String email);
@Query("select * from basic_user u where u.birthday = ?")
List<BasicUser> findByBirthday(LocalDate birthday);
}
Query By Example
BasicUser user = RandomData.randomUser();
user.setName("example");
requeryTemplate.insert(user);
BasicUser exampleUser = new BasicUser();
exampleUser.setName("EXA");
ExampleMatcher matcher = matching()
.withMatcher("name", startsWith().ignoreCase())
.withIgnoreNullValues();
Example<BasicUser> example = Example.of(exampleUser, matcher);
Return<? extends Result<BasicUser>> query = buildQueryByExample(example);
BasicUser foundUser = query.get().firstOrNull();
assertThat(foundUser).isNotNull().isEqualTo(user);
Query by Property
List<User> findByFirstnameOrLastname(String firstname, String lastname);
List<User> findByLastnameLikeOrderByFirstnameDesc(String lastname);
List<User> findByLastnameNotLike(String lastname);
List<User> findByLastnameNot(String lastname);
List<User> findByManagerLastname(String name);
List<User> findByColleaguesLastname(String lastname);
List<User> findByLastnameNotNull();
@Query("select u.lastname from SD_User u group by u.lastname")
Page<String> findByLastnameGrouped(Pageable pageable);
long countByLastname(String lastname);
int countUsersByFirstname(String firstname);
boolean existsByLastname(String lastname);
Note: Association Path is not supported
Note: Association Path is not supported
Exists
static class ExistsExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
return !query.createQuery(values).getResultList().isEmpty();
}
}
static class ExistsExecution extends RequeryQueryExecution {
@Override
protected @Nullable Object doExecute(AbstractRequeryQuery query, Object[] values) {
Result<?> result = (Result<?>) query.createQueryElement(values).limit(1).get();
return result.firstOrNull() != null;
}
}
Spring Data JPA - ExistsExecution
Spring Data Requery - ExistsExecution
Delete in JPA
static class DeleteExecution extends JpaQueryExecution {
private final EntityManager em;
public DeleteExecution(EntityManager em) {
this.em = em;
}
@Override
protected Object doExecute(AbstractJpaQuery jpaQuery, Object[] values) {
Query query = jpaQuery.createQuery(values);
List<?> resultList = query.getResultList();
for (Object o : resultList) {
em.remove(o);
}
return jpaQuery.getQueryMethod().isCollectionQuery() ? resultList : resultList.size();
}
}
Spring Data JPA - DeleteExecution
Load all entities to delete for
cascading delete
Delete in requery
static class DeleteExecution extends RequeryQueryExecution {
private final RequeryOperations operations;
DeleteExecution(@NotNull RequeryOperations operations) {
Assert.notNull(operations, "operations must not be null!");
this.operations = operations;
}
@SuppressWarnings("unchecked")
@Override
protected @Nullable Object doExecute(AbstractRequeryQuery query, Object[] values) {
QueryElement<?> whereClause = query.createQueryElement(values);
QueryElement<?> deleteQuery = applyWhereClause((QueryElement<?>) operations.delete(query.getDomainClass()),
whereClause.getWhereElements());
Scalar<Integer> result = ((QueryElement<? extends Scalar<Integer>>) deleteQuery).get();
return result.value();
}
}
Spring Data Requery - DeleteExecution
Use delete statements directly

cascading depends on DB
Future works
• Support Named parameter (ready)

• Support `@Param` in spring data 

• Support complecated aggregation operations

• Requery for Apache Phoenix (done)

• CoroutineEntityStore (testing)
Resources
• requery.io 

• spring-data-requery in github

• 2.0.x for spring-data-commons 2.0.x

• 2.1.x for spring-data-commons 2.1.x
Q&A
Thank you!

More Related Content

What's hot

A brief tour of modern Java
A brief tour of modern JavaA brief tour of modern Java
A brief tour of modern Java
Sina Madani
 
Hibernate 3
Hibernate 3Hibernate 3
Hibernate 3
Rajiv Gupta
 
All about scala
All about scalaAll about scala
All about scala
Yardena Meymann
 
Scala introduction
Scala introductionScala introduction
Scala introduction
Yardena Meymann
 
Hibernate inheritance and relational mappings with examples
Hibernate inheritance and relational mappings with examplesHibernate inheritance and relational mappings with examples
Hibernate inheritance and relational mappings with examples
Er. Gaurav Kumar
 
Hibernate
HibernateHibernate
Hibernate
Prashant Kalkar
 
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
Sagar Verma
 
Slickdemo
SlickdemoSlickdemo
Slickdemo
Knoldus Inc.
 
Hibernate in Nutshell
Hibernate in NutshellHibernate in Nutshell
Hibernate in Nutshell
Onkar Deshpande
 
Hibernate tutorial
Hibernate tutorialHibernate tutorial
Hibernate tutorial
Mumbai Academisc
 
JSR-222 Java Architecture for XML Binding
JSR-222 Java Architecture for XML BindingJSR-222 Java Architecture for XML Binding
JSR-222 Java Architecture for XML Binding
Heiko Scherrer
 
Unraveling the mystery of monads
Unraveling the mystery of monadsUnraveling the mystery of monads
Unraveling the mystery of monadsFaisal Waris
 
Hibernate Developer Reference
Hibernate Developer ReferenceHibernate Developer Reference
Hibernate Developer Reference
Muthuselvam RS
 
JUG Berlin Brandenburg: What's new in Java EE 7?
JUG Berlin Brandenburg: What's new in Java EE 7?JUG Berlin Brandenburg: What's new in Java EE 7?
JUG Berlin Brandenburg: What's new in Java EE 7?
gedoplan
 
Introduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examplesIntroduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examples
ecosio GmbH
 
Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?
Mario Camou Riveroll
 
CSharp Advanced L05-Attributes+Reflection
CSharp Advanced L05-Attributes+ReflectionCSharp Advanced L05-Attributes+Reflection
CSharp Advanced L05-Attributes+Reflection
Mohammad Shaker
 
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
Sagar Verma
 
Hibernate Tutorial
Hibernate TutorialHibernate Tutorial
Hibernate TutorialRam132
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
Stuart Roebuck
 

What's hot (20)

A brief tour of modern Java
A brief tour of modern JavaA brief tour of modern Java
A brief tour of modern Java
 
Hibernate 3
Hibernate 3Hibernate 3
Hibernate 3
 
All about scala
All about scalaAll about scala
All about scala
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
Hibernate inheritance and relational mappings with examples
Hibernate inheritance and relational mappings with examplesHibernate inheritance and relational mappings with examples
Hibernate inheritance and relational mappings with examples
 
Hibernate
HibernateHibernate
Hibernate
 
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
Java Class 6 | Java Class 6 |Threads in Java| Applets | Swing GUI | JDBC | Ac...
 
Slickdemo
SlickdemoSlickdemo
Slickdemo
 
Hibernate in Nutshell
Hibernate in NutshellHibernate in Nutshell
Hibernate in Nutshell
 
Hibernate tutorial
Hibernate tutorialHibernate tutorial
Hibernate tutorial
 
JSR-222 Java Architecture for XML Binding
JSR-222 Java Architecture for XML BindingJSR-222 Java Architecture for XML Binding
JSR-222 Java Architecture for XML Binding
 
Unraveling the mystery of monads
Unraveling the mystery of monadsUnraveling the mystery of monads
Unraveling the mystery of monads
 
Hibernate Developer Reference
Hibernate Developer ReferenceHibernate Developer Reference
Hibernate Developer Reference
 
JUG Berlin Brandenburg: What's new in Java EE 7?
JUG Berlin Brandenburg: What's new in Java EE 7?JUG Berlin Brandenburg: What's new in Java EE 7?
JUG Berlin Brandenburg: What's new in Java EE 7?
 
Introduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examplesIntroduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examples
 
Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?
 
CSharp Advanced L05-Attributes+Reflection
CSharp Advanced L05-Attributes+ReflectionCSharp Advanced L05-Attributes+Reflection
CSharp Advanced L05-Attributes+Reflection
 
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
Collection Framework in Java | Generics | Input-Output in Java | Serializatio...
 
Hibernate Tutorial
Hibernate TutorialHibernate Tutorial
Hibernate Tutorial
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 

Similar to Naver_alternative_to_jpa

Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
Eberhard Wolff
 
Jdbc presentation
Jdbc presentationJdbc presentation
Jdbc presentation
nrjoshiee
 
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
Oracle Developers
 
OrientDB - The 2nd generation of (multi-model) NoSQL
OrientDB - The 2nd generation of  (multi-model) NoSQLOrientDB - The 2nd generation of  (multi-model) NoSQL
OrientDB - The 2nd generation of (multi-model) NoSQL
Roberto Franchini
 
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
Using the latest Java Persistence API 2 Features - Tech Days 2010 IndiaUsing the latest Java Persistence API 2 Features - Tech Days 2010 India
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
Arun Gupta
 
SQL for Web APIs - Simplifying Data Access for API Consumers
SQL for Web APIs - Simplifying Data Access for API ConsumersSQL for Web APIs - Simplifying Data Access for API Consumers
SQL for Web APIs - Simplifying Data Access for API Consumers
Jerod Johnson
 
Database Programming Techniques
Database Programming TechniquesDatabase Programming Techniques
Database Programming Techniques
Raji Ghawi
 
Using the latest Java Persistence API 2.0 features
Using the latest Java Persistence API 2.0 featuresUsing the latest Java Persistence API 2.0 features
Using the latest Java Persistence API 2.0 featuresArun Gupta
 
Understanding
Understanding Understanding
Understanding Arun Gupta
 
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
Red Hat Developers
 
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
Christian Tzolov
 
What’s new in Java SE, EE, ME, Embedded world & new Strategy
What’s new in Java SE, EE, ME, Embedded world & new StrategyWhat’s new in Java SE, EE, ME, Embedded world & new Strategy
What’s new in Java SE, EE, ME, Embedded world & new Strategy
Mohamed Taman
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Spring Framework 4.0 to 4.1
Spring Framework 4.0 to 4.1Spring Framework 4.0 to 4.1
Spring Framework 4.0 to 4.1
Sam Brannen
 
S313431 JPA 2.0 Overview
S313431 JPA 2.0 OverviewS313431 JPA 2.0 Overview
S313431 JPA 2.0 Overview
Ludovic Champenois
 
Implementing a JavaScript Engine
Implementing a JavaScript EngineImplementing a JavaScript Engine
Implementing a JavaScript Engine
Kris Mok
 
Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpa
Staples
 

Similar to Naver_alternative_to_jpa (20)

Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
 
Jdbc presentation
Jdbc presentationJdbc presentation
Jdbc presentation
 
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
Reactive Java Programming: A new Asynchronous Database Access API by Kuassi M...
 
OrientDB - The 2nd generation of (multi-model) NoSQL
OrientDB - The 2nd generation of  (multi-model) NoSQLOrientDB - The 2nd generation of  (multi-model) NoSQL
OrientDB - The 2nd generation of (multi-model) NoSQL
 
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
Using the latest Java Persistence API 2 Features - Tech Days 2010 IndiaUsing the latest Java Persistence API 2 Features - Tech Days 2010 India
Using the latest Java Persistence API 2 Features - Tech Days 2010 India
 
SQL for Web APIs - Simplifying Data Access for API Consumers
SQL for Web APIs - Simplifying Data Access for API ConsumersSQL for Web APIs - Simplifying Data Access for API Consumers
SQL for Web APIs - Simplifying Data Access for API Consumers
 
Linq
LinqLinq
Linq
 
Database Programming Techniques
Database Programming TechniquesDatabase Programming Techniques
Database Programming Techniques
 
Using the latest Java Persistence API 2.0 features
Using the latest Java Persistence API 2.0 featuresUsing the latest Java Persistence API 2.0 features
Using the latest Java Persistence API 2.0 features
 
Understanding
Understanding Understanding
Understanding
 
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
Full Stack Development With Node.Js And NoSQL (Nic Raboy & Arun Gupta)
 
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
Using Apache Calcite for Enabling SQL and JDBC Access to Apache Geode and Oth...
 
What’s new in Java SE, EE, ME, Embedded world & new Strategy
What’s new in Java SE, EE, ME, Embedded world & new StrategyWhat’s new in Java SE, EE, ME, Embedded world & new Strategy
What’s new in Java SE, EE, ME, Embedded world & new Strategy
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Spring Framework 4.0 to 4.1
Spring Framework 4.0 to 4.1Spring Framework 4.0 to 4.1
Spring Framework 4.0 to 4.1
 
S313431 JPA 2.0 Overview
S313431 JPA 2.0 OverviewS313431 JPA 2.0 Overview
S313431 JPA 2.0 Overview
 
Implementing a JavaScript Engine
Implementing a JavaScript EngineImplementing a JavaScript Engine
Implementing a JavaScript Engine
 
Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpa
 
10 jdbc
10 jdbc10 jdbc
10 jdbc
 
10 jdbc
10 jdbc10 jdbc
10 jdbc
 

More from NAVER Engineering

React vac pattern
React vac patternReact vac pattern
React vac pattern
NAVER Engineering
 
디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX
NAVER Engineering
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)
NAVER Engineering
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트
NAVER Engineering
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호
NAVER Engineering
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라
NAVER Engineering
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기
NAVER Engineering
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정
NAVER Engineering
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
NAVER Engineering
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
NAVER Engineering
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
NAVER Engineering
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
NAVER Engineering
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
NAVER Engineering
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
NAVER Engineering
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
NAVER Engineering
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
NAVER Engineering
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
NAVER Engineering
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
NAVER Engineering
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
NAVER Engineering
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
NAVER Engineering
 

More from NAVER Engineering (20)

React vac pattern
React vac patternReact vac pattern
React vac pattern
 
디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
 

Recently uploaded

PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
Bhaskar Mitra
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 

Recently uploaded (20)

PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 

Naver_alternative_to_jpa

  • 1. Alternatives to JPA NaverTech talk debop@coupang.com 2019.01.22
  • 3. Agenda • What is ORM • Pros / Cons of JPA • Current status in Coupang • Alternatives of JPA • Slick • jOOQ • Exposed • Requery
  • 4. ORM (Object Relational Mapping) • OOP’s object graph vs Relational Database • Focus OOP, not Relational Database • No matter of RDBMS vendor - Same code • Hibernate coverage is 95% over traditional SQL statements • ORM not suitable for data centric application in performance • Why should you use an ORM?
  • 5. Pros of JPA • Focus to Java Object graph & OOP • No need to know relations and constraints of entities • No need to know specific DB features by various vendor • No need to know SQL, just use Java API • Supplement by HQL or JPQL or QueryDSL • All support for Stateful, Stateless (Default is Stateful)
  • 6. Cons of JPA • If you knew SQL already, JPA is wired • Hard to learning (exponential) • Low performance by stateful and fetch by id • No suitable for Bulk or Set operations • Massive Insert, Statistical Summary (Cube …) • Non-Threadsafe Session - Low throughput • Need to learn specific JPAVendor (Hibernate, Eclipse Link) • HQL, @DynamicInsert, @LazyCollection • 2nd Cache (recommend JCache (JSR-305))
  • 7. Current Status in Coupang • No Deep Dive • Missing override (hashCode, equals, toString) • No using @NatualId • Bad Policy / Bad Design • Every entity has Own identifier (Some case no need) • Poor performance -> Mislead “JPA is bad” • Apply not suitable case • Bulk operations, Statistical operations • No use supplement features • StatelessSession, 2nd Cache …
  • 8. DB: H2 Memory DB, CPU Core: 12, OS: Linux Mint, JVM: Java 8 0 5,000 10,000 15,000 20,000 25,000 30,000 35,000 40,000 45,000 50,000 10 1000 5000 JPA vs Requery Insert Benchmark JPA Requery
  • 9. Features in Alternatives of JPA • Design Principle • OOP based, Support Multi DBVendor • No need stateful for Reference object • Support association, inheritance, converter in JPA • Performance • Speed up to Plain SQL • Stateless • Support Asynchronous or Reactive • Support Bulk or Batch operations
  • 11. Slick • Database access library • Not ORM -> Functional Relational Mapping • Bring relational model to Scala OOP • Natural fit ( no impedance mismatch) • Stateless • Matures (Slick version 3) (Non-blocking DBIO) • Essential Slick Book
  • 12. Slick - schema definition Entity Schema Definition
  • 13. Slick - Query // Get Users with age > 20 Query statement Async Operations
  • 16. Slick - Plain SQL ResultSet to Tuple ResultSet to Entity
  • 18. jOOQ • Reflect Database Schema to generate Entity Class • Typesfe SQL (akaTypesafe MyBatis) • Database First (Not ORM) • Stateless • Need DBMS Owner Authority • jOOQ vs Hibernate :When to choose which
  • 19. jOOQ - typesafe SQL SELECT * FROM BOOK WHERE BOOK.PUBLISHED_IN = 2011 ORDER BY BOOK.TITLE create.selectFrom(BOOK) .where(BOOK.PUBLISHED_IN.eq(2011)) .orderBy(BOOK.TITLE) select().from(t).where(t.a.eq(select(t2.x).from(t2)); // Type-check here: ---------------> ^^^^ select().from(t).where(t.a.eq(any(select(t2.x).from(t2))); // Type-check here: -------------------> ^^^^ select().from(t).where(t.a.in(select(t2.x).from(t2)); // Type-check here: ---------------> ^^^^ select(t1.a).from(t1).unionAll(select(t2.a).from(t2)); // Type-check here: ----------------> ^^^^ select(t1.a, t1.b).from(t1).union(select(t2.a, t2.b).from(t2)); // Type-check here: -------------------> ^^^^^^^^^^ Predicates Set operations
  • 20. requery ORM for Java & Kotlin & Android
  • 21. requery • No reflection (apt code generation) - Fast instancing • Fast startup & performance • Schema generation • Blocking / Non-blocking API (Reactive with RxJava) • Support partial object / refresh / upsert • Custom type converter like JPA • Compile time entity validation • Support almost JPA annotations
  • 22. @Entity abstract class AbstractPerson {      @Key @Generated int id;          @Index("name_index") // table specification      String name;              @OneToMany // relationships 1:1, 1:many, many to many        Set<Phone> phoneNumbers;         @Converter(EmailToStringConverter.class)     Email email;     @PostLoad // lifecycle callbacks     void afterLoad() { updatePeopleList(); }     // getter, setters, equals & hashCode automatically generated into Person.java  } requery - define entity Identifier Entity class Converter Listeners
  • 23. Result<Person> query = data     .select(Person.class)     .where(Person.NAME.lower().like("b%"))     .and(Person.AGE.gt(20))     .orderBy(Person.AGE.desc())     .limit(5)     .get(); Observable<Person> observable = data     .select(Person.class)     .orderBy(Person.AGE.desc())     .get()     .observable(); requery - query Query by Fluent API Reactive Programming Cold Observable Non blocking
  • 24. @Entity(model = "tree")
 interface TreeNode {
     @get:Key
     @get:Generated
     val id: Long         @get:Column
     var name: String
 
     @get:ManyToOne(cascade = [DELETE])     var parent: TreeNode?
 
     @get:OneToMany(mappedBy = "parent", cascade = [SAVE, DELETE])
     val children: MutableSet<TreeNode> } requery - self refence by Kotlin Identifier Entity class 1:N, N:1 Cascade
  • 25. requery - Blob/Clob usage class ByteArrayBlobConverter : Converter<ByteArray, Blob> { override fun getPersistedSize(): Int? = null override fun getPersistedType(): Class<Blob> = Blob::class.java override fun getMappedType(): Class<ByteArray> = ByteArray::class.java override fun convertToMapped(type: Class<out ByteArray>?, value: Blob?): ByteArray? { return value?.binaryStream?.readBytes() } override fun convertToPersisted(value: ByteArray?): Blob? { return value?.let { SerialBlob(it) } } }
  • 26. requery - Blob property @Entity(model = "kt") interface BigModel { @get:Key @get:Generated @get:Column(name = "model_id") val id: Int @get:Column(name = "model_name") var name: String? @get:Convert(value = ByteArrayBlobConverter::class) @get:Column(name = "model_picture") var picture: ByteArray? } Blob column
  • 28. Exposed - Kotlin SQL Framework • Lightweight SQL Library • Provide two layers of data access • Typesafe SQL wrapping DSL • Lightweight Data Access Object • See : First steps with Kotlin/Exposed • Cons • Not mature
  • 29. Exposed - SQL DSL object Users : Table() {     val id = varchar("id", 10).primaryKey() // Column<String>      val name = varchar("name", length = 50) // Column<String>     val cityId = (integer("city_id") references Cities.id).nullable() // Column<Int?> } object Cities : Table() {      val id = integer("id").autoIncrement().primaryKey() // Column<Int>     val name = varchar("name", 50) // Column<String>  }
  • 30. Exposed - SQL DSL val munichId = Cities.insert {     it[name] = "Munich" } get Cities.id  Cities.insert { it[name] = "Prague" }  Users.insert {      it[id] = "andrey"      it[name] = "Andrey"      it[cityId] = saintPetersburgId  } Users.insert {      it[id] = "sergey"     it[name] = "Sergey"      it[cityId] = munichId }
  • 31. Exposed - SQL DSL - Join (Users innerJoin Cities)     .slice(Users.name, Cities.name)     .select {         (Users.id.eq("andrey") or Users.name.eq("Sergey")) and         Users.id.eq("sergey") and Users.cityId.eq(Cities.id)     }     .forEach {          println("${it[Users.name]} lives in ${it[Cities.name]}")     }
  • 32. Exposed - SQL DSL - Join 2 ((Cities innerJoin Users)     .slice(Cities.name, Users.id.count())     .selectAll()     .groupBy(Cities.name))     .forEach {         val cityName = it[Cities.name]         val userCount = it[Users.id.count()]         if (userCount > 0) {             println("$userCount user(s) live(s) in $cityName")         } else {              println("Nobody lives in $cityName")         }      }
  • 33. Exposed - DAO object Users : IntIdTable() {     val name = varchar("name", 50).index()     val city = reference("city", Cities)     val age = integer("age") } object Cities: IntIdTable() {      val name = varchar("name", 50) } Schema Definition class User(id: EntityID<Int>) : IntEntity(id){     companion object : IntEntityClass<User>(Users)     var name by Users.name     var city by City referencedOn Users.city     var age by Users.age  } class City(id: EntityID<Int>) : IntEntity(id) {     companion object : IntEntityClass<City>(Cities)     var name by Cities.name     val users by User referrersOn Users.city  } Entity Definition
  • 34. Exposed - DAO Usage val munich = City.new {     name = "Munich" } User.new {     name = "a"     city = munich     age = 5 } User.new {     name = "b"     city = munich     age = 27 } munich.users.joinToString { it.name } User.find { Users.age.between(18, 60) } OneTo Many All user’s name in Munich
  • 35. Conclusion • Already legacy database exists ? Use only Java • jOOQ or requery • Scala only ? -> Slick • Kotlin only ? -> requery, Exposed • No matter language? -> requery • Need Reactive programming? -> • requery with kotlinx-requery • kotlinx-rxjava2-jdbc ( we will open March )
  • 37. Agenda • Requery Overview • Why Requery • Define Mapping • Usage EntityDataStore • EntityDataStore for Kotlin (Coroutines) • Introduction of Spring Data Requery
  • 38. Requery Overview • ORM Library for Java, Kotlin, Android • No Reflection (vs Hibernate proxy) • Typed Query language (vs Hibernate Criteria) • Upsert/Partial objects refresh • Compile time entity/query validation (vs Hibernate) • Entity is stateless (vs Hibernate stateful) • Thread 에 제한 받지 않음 (vs JPA EntityManager) • Support RxJava, Async Operations, Java 8
  • 39. Why Requery • Provide benefit of ORM • Entity Mapping • Schema Generation • Compile time error detecting • Performance • When bulk job, max 100x than JPA • REST API - 2~10x throughput • Support Upsert, Lazy loading …
  • 40. DB: H2 Memory DB, CPU Core: 12, OS: Linux Mint, JVM: Java 8 0 5,000 10,000 15,000 20,000 25,000 30,000 35,000 40,000 45,000 50,000 10 1000 5000 JPA vs Requery Insert Benchmark JPA Requery
  • 41. Define Entity - Java @Getter @Entity(name = "BasicUser", copyable = true) @Table(name = "basic_user") public abstract class AbstractBasicUser extends AuditableLongEntity { @Key @Generated protected Long id; protected String name; protected String email; protected LocalDate birthday; protected Integer age; @ForeignKey @OneToOne protected AbstractBasicLocation address; @ManyToMany(mappedBy = "members") protected Set<AbstractBasicGroup> groups; @Column(unique = true) protected UUID uuid;
  • 42. Define Entity - Kotlin @Entity(model = "functional") interface Person: Persistable { @get:Key @get:Generated val id: Long @get:Index(value = ["idx_person_name_email"]) var name: String @get:Index(value = ["idx_person_name_email", "idx_person_email"]) var email: String var birthday: LocalDate @get:Column(value = "'empty'") var description: String? @get:Nullable var age: Int? @get:ForeignKey @get:OneToOne(mappedBy = "person", cascade = [CascadeAction.DELETE, CascadeAction.SAVE]) var address: Address? @get:OneToMany(mappedBy = "owner", cascade = [CascadeAction.DELETE, CascadeAction.SAVE]) val phoneNumbers: MutableSet<Phone> @get:OneToMany val phoneNumberList: MutableList<Phone> @get:ManyToMany(mappedBy = "members") val groups: MutableResult<Group> @get:ManyToMany(mappedBy = "owners") val ownedGroups: MutableResult<Group> @get:ManyToMany(mappedBy = "id") @get:JunctionTable val friends: MutableSet<Person> @get:Lazy var about: String? @get:Column(unique = true) var uuid: UUID var homepage: URL var picture: String }
  • 43. EntityDataStore<Object> • findByKey • select / insert / update / upsert / delete • where / eq, lte, lt, gt, gte, like, in, not … • groupBy / having / limit / offset • support SQL Functions • count, sum, avg, upper, lower … • raw query
  • 44. @Test fun `insert user`() { val user = RandomData.randomUser() withDb(Models.DEFAULT) { insert(user) assertThat(user.id).isGreaterThan(0) val loaded = select(User::class) where (User::id eq user.id) limit 10 assertThat(loaded.get().first()).isEqualTo(user) } } val result = select(Location::class) .join(User::class).on(User::location eq Location::id) .where(User::id eq user.id) .orderBy(Location::city.desc()) .get() val result = raw(User::class, "SELECT * FROM Users") val rowCount = update(UserEntity::class) .set(UserEntity.ABOUT, "nothing") .set(UserEntity.AGE, 50) .where(UserEntity.AGE eq 100) .get() .value() val count = insert(PersonEntity::class, PersonEntity.NAME, PersonEntity.DESCRIPTION) .query(select(GroupEntity.NAME, GroupEntity.DESCRIPTION)) .get() .first() .count()
  • 45. CoroutineEntityDataStore val store = CoroutineEntityStore(this) runBlocking { val users = store.insert(RandomData.randomUsers(10)) users.await().forEach { user -> assertThat(user.id).isGreaterThan(0) } store .count(UserEntity::class) .get() .toDeferred() .await() .let { assertThat(it).isEqualTo(10) } } with(coroutineTemplate) { val user = randomUser() // can replace with `withContext { }` async { insert(user) }.await() assertThat(user.id).isNotNull() val group = RandomData.randomGroup() group.members.add(user) async { insert(group) }.await() assertThat(user.groups).hasSize(1) assertThat(group.members).hasSize(1) }
  • 46. spring-data-requery • RequeryOperations • Wrap EntityDataStore • RequeryTransactionManager for TransactionManager • Support Spring @Transactional • Better performance than spring-data-jpa • when exists, paging, not load all entities
  • 47. spring-data-requery • Repository built in SQL • ByPropertyName Auto generation methods • @Query for Native SQL Query • Query By Example • Not Supported • Association Path (not specified join method) • Named parameter in @Query (just use `?`) (support next version)
  • 48. Setup spring-data-requery @Configuration @EnableTransactionManagement public class RequeryTestConfiguration extends AbstractRequeryConfiguration { @Override @Bean public EntityModel getEntityModel() { return Models.DEFAULT; } @Override public TableCreationMode getTableCreationMode() { return TableCreationMode.CREATE_NOT_EXISTS; } @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } }
  • 49. Provided Beans @Bean public io.requery.sql.Configuration requeryConfiguration() { return new ConfigurationBuilder(dataSource, getEntityModel()) // .useDefaultLogging() .setEntityCache(new EmptyEntityCache()) .setStatementCacheSize(1024) .setBatchUpdateSize(100) .addStatementListener(new LogbackListener()) .build(); } @Bean public EntityDataStore<Object> entityDataStore() { log.info("Create EntityDataStore instance."); return new EntityDataStore<>(requeryConfiguration()); } @Bean public RequeryOperations requeryOperations() { log.info("Create RequeryTemplate instance."); return new RequeryTemplate(entityDataStore(), requeryMappingContext()); } EntityCache 설정Tip : 개발 시에는 EmptyEntityCache, 운영 시에는 Cache2kEntityCache 사용
  • 50. Use @Query in Repository interface DeclaredQueryRepository extends RequeryRepository<BasicUser, Long> { @Query("select * from basic_user u where u.email = ?") BasicUser findByAnnotatedQuery(String email); @Query("select * from basic_user u where u.email like ?") List<BasicUser> findAllByEmailMatches(String email); @Query("select * from basic_user u limit ?") List<BasicUser> findWithLimits(int limit); @Query("select * from basic_user u where u.name=? and u.email=? limit 1") BasicUser findAllBy(String name, String email); @Query("select u.id, u.name from basic_user u where u.email=?") List<Tuple> findAllIds(String email); @Query("select * from basic_user u where u.birthday = ?") List<BasicUser> findByBirthday(LocalDate birthday); }
  • 51. Query By Example BasicUser user = RandomData.randomUser(); user.setName("example"); requeryTemplate.insert(user); BasicUser exampleUser = new BasicUser(); exampleUser.setName("EXA"); ExampleMatcher matcher = matching() .withMatcher("name", startsWith().ignoreCase()) .withIgnoreNullValues(); Example<BasicUser> example = Example.of(exampleUser, matcher); Return<? extends Result<BasicUser>> query = buildQueryByExample(example); BasicUser foundUser = query.get().firstOrNull(); assertThat(foundUser).isNotNull().isEqualTo(user);
  • 52. Query by Property List<User> findByFirstnameOrLastname(String firstname, String lastname); List<User> findByLastnameLikeOrderByFirstnameDesc(String lastname); List<User> findByLastnameNotLike(String lastname); List<User> findByLastnameNot(String lastname); List<User> findByManagerLastname(String name); List<User> findByColleaguesLastname(String lastname); List<User> findByLastnameNotNull(); @Query("select u.lastname from SD_User u group by u.lastname") Page<String> findByLastnameGrouped(Pageable pageable); long countByLastname(String lastname); int countUsersByFirstname(String firstname); boolean existsByLastname(String lastname); Note: Association Path is not supported Note: Association Path is not supported
  • 53. Exists static class ExistsExecution extends JpaQueryExecution { @Override protected Object doExecute(AbstractJpaQuery query, Object[] values) { return !query.createQuery(values).getResultList().isEmpty(); } } static class ExistsExecution extends RequeryQueryExecution { @Override protected @Nullable Object doExecute(AbstractRequeryQuery query, Object[] values) { Result<?> result = (Result<?>) query.createQueryElement(values).limit(1).get(); return result.firstOrNull() != null; } } Spring Data JPA - ExistsExecution Spring Data Requery - ExistsExecution
  • 54. Delete in JPA static class DeleteExecution extends JpaQueryExecution { private final EntityManager em; public DeleteExecution(EntityManager em) { this.em = em; } @Override protected Object doExecute(AbstractJpaQuery jpaQuery, Object[] values) { Query query = jpaQuery.createQuery(values); List<?> resultList = query.getResultList(); for (Object o : resultList) { em.remove(o); } return jpaQuery.getQueryMethod().isCollectionQuery() ? resultList : resultList.size(); } } Spring Data JPA - DeleteExecution Load all entities to delete for cascading delete
  • 55. Delete in requery static class DeleteExecution extends RequeryQueryExecution { private final RequeryOperations operations; DeleteExecution(@NotNull RequeryOperations operations) { Assert.notNull(operations, "operations must not be null!"); this.operations = operations; } @SuppressWarnings("unchecked") @Override protected @Nullable Object doExecute(AbstractRequeryQuery query, Object[] values) { QueryElement<?> whereClause = query.createQueryElement(values); QueryElement<?> deleteQuery = applyWhereClause((QueryElement<?>) operations.delete(query.getDomainClass()), whereClause.getWhereElements()); Scalar<Integer> result = ((QueryElement<? extends Scalar<Integer>>) deleteQuery).get(); return result.value(); } } Spring Data Requery - DeleteExecution Use delete statements directly
 cascading depends on DB
  • 56. Future works • Support Named parameter (ready) • Support `@Param` in spring data • Support complecated aggregation operations
 • Requery for Apache Phoenix (done) • CoroutineEntityStore (testing)
  • 57. Resources • requery.io • spring-data-requery in github • 2.0.x for spring-data-commons 2.0.x • 2.1.x for spring-data-commons 2.1.x
  • 58. Q&A