Skip to content

Commit 92941ba

Browse files
author
bretislav.wajtr
committed
#3 Ebean implementation
+ Changed autowiring of beans to be constructor based + Made build.gradle more readable (I hope)
1 parent f1827fb commit 92941ba

15 files changed

Lines changed: 903 additions & 50 deletions

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Comparison of how **non-JPA** SQL mapping (persistence) frameworks for Java (Joo
44

55
I'm not comparing performance, but rather how are these frameworks used for everyday tasks.
66

7-
I prepared some common scenarios, which you typically need to implement data-centric application, and then we implemented these scenarios using various non-JPA DB layer frameworks. This project should serve
7+
I prepared some common scenarios, which you typically need to implement data-centric application, and then I implemented these scenarios using various non-JPA DB layer frameworks. This project should serve
88
- as point of reference when deciding for SQL mapping framework
99
- as a template of common framework usage scenarios (see scenarios below)
1010
- to document best practices of such common usages (**comments are welcomed!**)
@@ -23,6 +23,7 @@ With that conditions in respect, following frameworks were compared:
2323
* **Spring JDBCTemplate** (see [implementation](src/main/java/com/clevergang/dbtests/repository/impl/jdbctemplate/JDBCDataRepositoryImpl.java))
2424
* **jOOQ** (see [implementation](src/main/java/com/clevergang/dbtests/repository/impl/jooq/JooqDataRepositoryImpl.java))
2525
* **MyBatis** (see [implementation](src/main/java/com/clevergang/dbtests/repository/impl/mybatis/MyBatisDataRepositoryImpl.java) and [mapper](src/main/resources/mybatis/mappers/DataRepositoryMapper.xml))
26+
* **EBean** (see [implementation](src/main/java/com/clevergang/dbtests/repository/impl/ebean/EBeanDataRepositoryImpl.java))
2627

2728
I tried to find optimal (== most readable) implementation in every framework, but comments are welcomed! There are lot of comments in the code explaining why I chose such implementation and some FIXMEs on places which I do not like, but which cannot be implemented differently or which I have troubles to improve...
2829

@@ -57,7 +58,8 @@ Each scenario has it's implementation in the Scenarios class. See javadoc of [Sc
5758
2. Configure PostgreSQL connection details in [application.properties](src/main/resources/application.properties)
5859
3. Create tables and data by running [create-script.sql](sql-updates/create-script.sql)
5960
4. Create one stored procedure by running [register_employee.sql](sql-updates/sql_functions/register_employee.sql)
60-
5. Give the scenarios a test run by running one of the test classes and enjoy :)
61+
5. Tests will passing when executed from gradle build. If you want tests to be passing even from your IDE, then [setup EBean enhancer for your IDE](http://ebean-orm.github.io/docs/setup/enhancement)
62+
6. Give the scenarios a test run by running one of the test classes and enjoy :)
6163

6264
## Why only non-JPA?
6365

@@ -98,12 +100,24 @@ Please note that following remarks are very subjective and does not have to nece
98100
* Not so much usable for big queries - it's better to use native SQL (see scenario 9.)
99101
* Weird syntax for performing batch operations (in case that you do not use UpdatableRecord). But it's not a big deal...
100102

101-
102103
**MyBatis**
103104
* Pros
104105
* Writing SQL statements in XML mapper file feels good - it's easy to work with parameters.
105106
* Cons
106107
* quite a lot of files for single DAO imlementation (MyBatisDataRepositoryImpl, DataRepositoryMapper and DataRepositoryMapper.xml), though navigation is not such a big deal
107108
* at version 3.4.0 unable to work with Java8 DateTime types (LocalDate etc.), support possible through 3rd party library (mybatis-types), see build.gradle and <typeHandlers> configuration in mybatis-config.xml
108109
* can't run batch and non-batch operations in single SqlSession, but have to create completely new SqlSession instead (see configuration in DbTestsApplication class). Surprisingly, this does not necessarily mean that the batch and non-batch operations will be executed in different transactions (as we would expect), so at the end this is not a total drawback, but just inconvenience
109-
* expected that localCacheScope=STATEMENT is default MyBatis behavior, which is not... I know this is questionable drawback, but it was kind of surprise for me, see mybatis-config.xml
110+
* expected that localCacheScope=STATEMENT is default MyBatis behavior, which is not... I know this is questionable drawback, but it was kind of surprise for me, see mybatis-config.xml
111+
112+
**EBean**
113+
* Pros
114+
* Everything looks very nice - all the scenarios are implemented by very readable code
115+
* Super simple batch operations (actually it's only about using right method :) )
116+
* Although there are methods which make CRUD operations and Querying super simple, there are still means how to execute plain SQL and even a way how to get the basic JDBC Transaction object, which you can use for core JDBC stuff. That is really good.
117+
* Cons
118+
* Necessity to write the entities (I mean @Entity classes) - it would be cool to have some generator for it
119+
* Necessity of "enhancement" of the entities - this was quite surprising for me - but actually it's basically only about right environment setup (IDE plugin and Gradle plugin) and then you don't have to think about it
120+
* Online documentation is quite weak (as of December 1, 2016). Lot of things are hidden in videos and you have to google for details or get into JavaDocs... Hoverwer, JavaDoc is very good and I generally didn't a problem to find what I need in JavaDoc. Also the API is quite understandable... at the end weak online documentation is not such a big deal.
121+
* Logging could be better
122+
* Allows JPA OneToMany and ManyToOne relations modeling and possibility to "lazy fetch" these relations - actually I do not like this concept at all as it can lead to potentially very ineffective code. Per documentation and experiences of several people on internet EBean behaves better than full blown JPA implementation in this manner, but you can still be hit by the N+1 problem and all the performance traps, which lazy fetching brings...
123+

build.gradle

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,71 @@
1-
2-
buildscript {
3-
repositories {
4-
jcenter()
5-
}
6-
dependencies {
7-
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE" // to include SpringBoot parent BOM
8-
}
9-
}
10-
11-
apply plugin: 'spring-boot'
12-
apply plugin: 'java'
13-
141
group = 'com.clevergang'
152
version = '1.0.0'
163
description = 'Comparison and common patterns for non-JPA SQL mapping frameworks for Java (Jooq, Spring JDBCTemplate etc.)'
174

18-
repositories {
19-
jcenter()
20-
maven { url "https://jitpack.io" }
21-
}
5+
apply plugin: 'spring-boot'
6+
apply plugin: 'java'
7+
apply plugin: 'com.github.kt3k.ebean.enhance' // required so the enhancer works, see below
228

239
// We need Java8 for this project
2410
tasks.withType(JavaCompile) {
2511
sourceCompatibility = '1.8'
2612
}
2713

14+
// this is actually required for EBean to work. EBean needs all @Entity classes to be enhanced before usage
15+
// for gradle builds this is how the entities are enhanced. See more info here:
16+
// http://ebean-orm.github.io/docs/setup/enhancement
17+
// and here:
18+
// https://github.com/kt3k/ebean-enhance-plugin
19+
ebeanEnhance {
20+
packages = 'com.clevergang.dbtests.repository.impl.ebean.entities.**'
21+
agentVersion = '8.1.1'
22+
}
23+
2824
dependencies {
29-
compile "org.springframework.boot:spring-boot-starter-jdbc"
30-
compile "org.springframework.boot:spring-boot-starter-jooq"
31-
compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1'
32-
compile "org.postgresql:postgresql:9.4.1212"
33-
compile "org.apache.commons:commons-lang3:3.4"
34-
compile "org.apache.commons:commons-collections4:4.1"
25+
compile(
26+
"org.springframework.boot:spring-boot-starter-jdbc",
27+
"org.postgresql:postgresql:9.4.1212",
28+
"org.apache.commons:commons-lang3:3.4",
29+
"org.apache.commons:commons-collections4:4.1",
30+
31+
// jOOQ dependencies
32+
"org.springframework.boot:spring-boot-starter-jooq",
3533

36-
// required so mybatis works with java8 datetime classes (LocalDate)
37-
compile 'com.github.javaplugs:mybatis-types:0.3'
34+
// EBean dependencies
35+
"org.avaje.ebean:ebean:9.2.1",
36+
"org.avaje.ebean:ebean-spring:7.2.1",
3837

39-
testCompile "org.springframework.boot:spring-boot-starter-test"
38+
// MyBatis dependencies
39+
'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1',
40+
'com.github.javaplugs:mybatis-types:0.3' // required so mybatis works with java8 datetime classes (LocalDate)
41+
)
42+
43+
testCompile(
44+
"org.springframework.boot:spring-boot-starter-test"
45+
)
4046
}
4147

4248
// we want to show following test events in the log
4349
test {
4450
testLogging {
4551
events "PASSED", "FAILED", "SKIPPED"
4652
}
53+
}
54+
55+
buildscript {
56+
repositories {
57+
jcenter()
58+
maven {
59+
url "https://plugins.gradle.org/m2/"
60+
}
61+
}
62+
dependencies {
63+
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE" // to include SpringBoot parent BOM
64+
classpath "gradle.plugin.org.kt3k:ebean-enhance-plugin:2.0.5"
65+
}
66+
}
67+
68+
repositories {
69+
jcenter()
70+
maven { url "https://jitpack.io" }
4771
}

src/main/java/com/clevergang/dbtests/DbTestsApplication.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.clevergang.dbtests;
22

3+
import com.avaje.ebean.EbeanServer;
4+
import com.avaje.ebean.EbeanServerFactory;
5+
import com.avaje.ebean.config.ServerConfig;
6+
import com.avaje.ebean.springsupport.txn.SpringAwareJdbcTransactionManager;
37
import org.apache.ibatis.session.ExecutorType;
48
import org.apache.ibatis.session.SqlSession;
59
import org.apache.ibatis.session.SqlSessionFactory;
@@ -25,9 +29,9 @@
2529
@Configuration
2630
public class DbTestsApplication {
2731

28-
/**
32+
/*
2933
* JOOQ CONFIGURATIONS
30-
**/
34+
*/
3135

3236
@Bean
3337
@Primary
@@ -47,9 +51,9 @@ public Settings jooqStaticStatementSettings() {
4751
return ret;
4852
}
4953

50-
/**
54+
/*
5155
* MYBATIS CONFIGURATIONS
52-
**/
56+
*/
5357

5458
@Bean
5559
@Primary
@@ -78,6 +82,30 @@ executed in different transactions (as we would expect) - we tested this configu
7882
return new SqlSessionTemplate(sqlSessionFactoryBean.getObject(), ExecutorType.BATCH);
7983
}
8084

85+
/*
86+
* EBEAN CONFIGURATIONS
87+
*/
88+
89+
@SuppressWarnings("SpringJavaAutowiringInspection")
90+
@Bean
91+
public ServerConfig ebeanServerConfig(DataSource dataSource) {
92+
ServerConfig config = new ServerConfig();
93+
config.setName("ebeanServer");
94+
config.setDefaultServer(true);
95+
config.setDataSource(dataSource);
96+
config.addPackage("com.clevergang.dbtests.repository.impl.ebean.entities");
97+
config.setExternalTransactionManager(new SpringAwareJdbcTransactionManager());
98+
config.setAutoCommitMode(false);
99+
config.setExpressionNativeIlike(true);
100+
101+
return config;
102+
}
103+
104+
@Bean
105+
public EbeanServer ebeanServer(ServerConfig serverConfig) {
106+
return EbeanServerFactory.create(serverConfig);
107+
}
108+
81109
public static void main(String[] args) {
82110
SpringApplication.run(DbTestsApplication.class, args);
83111
}

src/main/java/com/clevergang/dbtests/Scenarios.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public void fetchListOfEntitiesScenario(Integer employeeMinSalary) {
6464
// check some post conditions
6565
assert employees != null;
6666
assert employees.size() == 3;
67+
assert employees.get(0).getSalary().compareTo(new BigDecimal(employeeMinSalary)) > 0;
68+
assert employees.get(1).getSalary().compareTo(new BigDecimal(employeeMinSalary)) > 0;
69+
assert employees.get(2).getSalary().compareTo(new BigDecimal(employeeMinSalary)) > 0;
6770
logger.info("Fetched result: {}", employees);
6871
}
6972

@@ -112,12 +115,17 @@ public void batchInsertMultipleEntitiesScenario() {
112115
}
113116

114117
// SCENARIO CODE STARTS HERE
118+
long start = System.nanoTime();
115119
List<Integer> newPids = repository.insertProjects(projects);
116120

117121
// check some post conditions
118122
Integer projectsCount = repository.getProjectsCount();
123+
long end = System.nanoTime();
124+
119125
assert projectsCount == 1002;
120126
logger.info("Scenario 4. output {}", newPids);
127+
logger.info("Rough time needed for execution (without commit): {} ms", (end - start) / 1000000d);
128+
121129
}
122130

123131
/**

0 commit comments

Comments
 (0)