Skip to content

Commit 970d1bf

Browse files
author
bretislav.wajtr
committed
Improved JDBCtemplate impelmentation - used MapSqlParameterSource which feels more fluent and also used BeanPropertyRowMapper.newInstance which seems nicer than using constructor.
Additionally used PostgreSQL JDBC driver in version which supports JDBC 4.2 where Java8 Date/Time classes are fully supported (like LocalDate). Improved verification of scenario three.
1 parent 9465d69 commit 970d1bf

9 files changed

Lines changed: 113 additions & 65 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ dependencies {
2929
compile "org.springframework.boot:spring-boot-starter-jdbc"
3030
compile "org.springframework.boot:spring-boot-starter-jooq"
3131
compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1'
32-
compile "org.postgresql:postgresql:9.4.1211.jre7"
32+
compile "org.postgresql:postgresql:9.4.1212"
3333
compile "org.apache.commons:commons-lang3:3.4"
3434
compile "org.apache.commons:commons-collections4:4.1"
3535

jooq.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ tasks.withType(JavaCompile) {
3434
}
3535

3636
dependencies {
37-
jooqRuntime "org.postgresql:postgresql:9.4.1211.jre7"
37+
jooqRuntime "org.postgresql:postgresql:9.4.1212"
3838
}
3939

4040
// jooq configuration

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,17 @@ public void saveNewEntityScenario() {
7979
Integer newPid = repository.insertProject(project);
8080

8181
// check some post conditions
82+
logger.info("Scenario three, pid of inserted entity: {}", newPid);
8283
assert newPid != null;
8384
assert newPid > 2;
84-
logger.info("Scenario three, pid of inserted entity: {}", newPid);
85+
86+
Project storedProject = repository.findProject(newPid);
87+
logger.info("Scenario three, stored project: {}", storedProject);
88+
89+
assert storedProject != null;
90+
assert newPid.equals(storedProject.getPid());
91+
assert project.getName().equals(storedProject.getName());
92+
assert project.getDate().equals(storedProject.getDate());
8593
}
8694

8795
/**
@@ -106,7 +114,7 @@ public void batchInsertMultipleEntitiesScenario() {
106114
// SCENARIO CODE STARTS HERE
107115
List<Integer> newPids = repository.insertProjects(projects);
108116

109-
// check some postconditions
117+
// check some post conditions
110118
Integer projectsCount = repository.getProjectsCount();
111119
assert projectsCount == 1002;
112120
logger.info("Scenario 4. output {}", newPids);

src/main/java/com/clevergang/dbtests/repository/api/DataRepository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ public interface DataRepository {
7676

7777
// Projects
7878

79+
/**
80+
* @param pid Primary key of the project record to be found
81+
* @return Should return full record of the Project record identified by pid
82+
*/
83+
Project findProject(Integer pid);
84+
7985
/**
8086
* Insert project and return PID of newly created item
8187
*

src/main/java/com/clevergang/dbtests/repository/impl/jdbctemplate/JDBCDataRepositoryImpl.java

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,12 @@
99
import org.springframework.jdbc.core.RowMapper;
1010
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
1111
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
12-
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
1312
import org.springframework.jdbc.support.GeneratedKeyHolder;
1413
import org.springframework.jdbc.support.KeyHolder;
1514
import org.springframework.stereotype.Repository;
1615

1716
import java.math.BigDecimal;
18-
import java.sql.Date;
19-
import java.util.HashMap;
2017
import java.util.List;
21-
import java.util.Map;
2218
import java.util.stream.Collectors;
2319

2420
/**
@@ -38,14 +34,16 @@ public class JDBCDataRepositoryImpl implements DataRepository {
3834
public Company findCompany(Integer pid) {
3935
logger.info("Finding Company by ID using JDBCTemplate");
4036

41-
String query;
42-
query = "SELECT pid, address, name " +
37+
String query = "SELECT pid, address, name " +
4338
"FROM company " +
4439
"WHERE pid = :pid";
4540

46-
Map<String, Object> params = new HashMap<>();
47-
params.put("pid", pid);
41+
MapSqlParameterSource params = new MapSqlParameterSource()
42+
.addValue("pid", pid);
4843

44+
/*
45+
* Note that you can use BeanPropertyRowMapper instead (see findDepartment())
46+
*/
4947
RowMapper<Company> mapper = (rs, rowNum) -> {
5048
Company row = new Company();
5149
row.setPid(rs.getInt("pid"));
@@ -90,16 +88,15 @@ public Company findCompanyUsingSimpleStaticStatement(Integer pid) {
9088

9189
@Override
9290
public Department findDepartment(Integer pid) {
93-
String query;
94-
query = "SELECT pid, company_pid, name" +
91+
String query = "SELECT pid, company_pid, name" +
9592
" FROM department " +
9693
" WHERE pid = :pid";
9794

98-
Map<String, Object> params = new HashMap<>();
99-
params.put("pid", pid);
95+
MapSqlParameterSource params = new MapSqlParameterSource()
96+
.addValue("pid", pid);
10097

10198
// using BeanPropertyRowMapper is easier, but with much worse performance than custom RowMapper
102-
return jdbcTemplate.queryForObject(query, params, new BeanPropertyRowMapper<>(Department.class));
99+
return jdbcTemplate.queryForObject(query, params, BeanPropertyRowMapper.newInstance(Department.class));
103100
}
104101

105102
@Override
@@ -110,11 +107,11 @@ public List<Employee> employeesWithSalaryGreaterThan(Integer minSalary) {
110107
" FROM employee" +
111108
" WHERE salary > :salary";
112109

113-
Map<String, Object> params = new HashMap<>();
114-
params.put("salary", minSalary);
110+
MapSqlParameterSource params = new MapSqlParameterSource()
111+
.addValue("salary", minSalary);
115112

116113
// using BeanPropertyRowMapper is easier, but with much worse performance than custom RowMapper
117-
return jdbcTemplate.query(query, params, new BeanPropertyRowMapper<>(Employee.class));
114+
return jdbcTemplate.query(query, params, BeanPropertyRowMapper.newInstance(Employee.class));
118115
}
119116

120117
@Override
@@ -124,15 +121,15 @@ public Integer insertProject(Project project) {
124121
String insertStatement = " INSERT INTO project (name, datestarted) " +
125122
" VALUES (:name, :datestarted)";
126123

127-
MapSqlParameterSource params = new MapSqlParameterSource();
128-
params.addValue("name", project.getName());
129-
params.addValue("datestarted", Date.valueOf(project.getDate()));
124+
MapSqlParameterSource params = new MapSqlParameterSource()
125+
.addValue("name", project.getName())
126+
.addValue("datestarted", project.getDate());
130127

131128
KeyHolder generatedKey = new GeneratedKeyHolder();
132129

133130
jdbcTemplate.update(insertStatement, params, generatedKey);
134131

135-
return (Integer)generatedKey.getKeys().get("pid");
132+
return (Integer) generatedKey.getKeys().get("pid");
136133
}
137134

138135
@Override
@@ -144,12 +141,9 @@ public List<Integer> insertProjects(List<Project> projects) {
144141

145142
MapSqlParameterSource[] paramsList = projects
146143
.stream()
147-
.map(project -> {
148-
MapSqlParameterSource params = new MapSqlParameterSource();
149-
params.addValue("name", project.getName());
150-
params.addValue("datestarted", Date.valueOf(project.getDate()));
151-
return params;
152-
})
144+
.map(project -> new MapSqlParameterSource()
145+
.addValue("name", project.getName())
146+
.addValue("datestarted", project.getDate()))
153147
.toArray(MapSqlParameterSource[]::new);
154148

155149
jdbcTemplate.batchUpdate(insertStatement, paramsList);
@@ -170,13 +164,13 @@ public void updateEmployee(Employee employeeToUpdate) {
170164
" salary = :salary" +
171165
" WHERE pid = :pid";
172166

173-
MapSqlParameterSource params = new MapSqlParameterSource();
174-
params.addValue("department_pid", employeeToUpdate.getDepartmentPid());
175-
params.addValue("name", employeeToUpdate.getName());
176-
params.addValue("surname", employeeToUpdate.getSurname());
177-
params.addValue("email", employeeToUpdate.getEmail());
178-
params.addValue("salary", employeeToUpdate.getSalary());
179-
params.addValue("pid", employeeToUpdate.getPid());
167+
MapSqlParameterSource params = new MapSqlParameterSource()
168+
.addValue("department_pid", employeeToUpdate.getDepartmentPid())
169+
.addValue("name", employeeToUpdate.getName())
170+
.addValue("surname", employeeToUpdate.getSurname())
171+
.addValue("email", employeeToUpdate.getEmail())
172+
.addValue("salary", employeeToUpdate.getSalary())
173+
.addValue("pid", employeeToUpdate.getPid());
180174

181175
jdbcTemplate.update(updateStatement, params);
182176
}
@@ -202,8 +196,8 @@ public List<ProjectsWithCostsGreaterThanOutput> getProjectsWithCostsGreaterThan(
202196
"GROUP BY project_name, total_cost, company_name\n" +
203197
"ORDER BY company_name";
204198

205-
Map<String, Object> params = new HashMap<>();
206-
params.put("totalCostBoundary", totalCostBoundary);
199+
MapSqlParameterSource params = new MapSqlParameterSource()
200+
.addValue("totalCostBoundary", totalCostBoundary);
207201

208202
RowMapper<ProjectsWithCostsGreaterThanOutput> mapper = (rs, rowNum) -> {
209203
ProjectsWithCostsGreaterThanOutput row = new ProjectsWithCostsGreaterThanOutput();
@@ -220,13 +214,13 @@ public List<ProjectsWithCostsGreaterThanOutput> getProjectsWithCostsGreaterThan(
220214
@Override
221215
public Employee findEmployee(Integer pid) {
222216
String query;
223-
query = "SELECT pid, email, name, salary, surname, department_pid as departmentPid FROM employee WHERE pid = :pid";
217+
query = "SELECT pid, email, name, salary, surname, department_pid AS departmentPid FROM employee WHERE pid = :pid";
224218

225-
Map<String, Object> params = new HashMap<>();
226-
params.put("pid", pid);
219+
MapSqlParameterSource params = new MapSqlParameterSource()
220+
.addValue("pid", pid);
227221

228222
// using BeanPropertyRowMapper is easier, but with much worse performance than custom RowMapper
229-
return jdbcTemplate.queryForObject(query, params, new BeanPropertyRowMapper<>(Employee.class));
223+
return jdbcTemplate.queryForObject(query, params, BeanPropertyRowMapper.newInstance(Employee.class));
230224
}
231225

232226
@Override
@@ -242,13 +236,14 @@ public RegisterEmployeeOutput callRegisterEmployee(String name, String surname,
242236
" _company_name := :companyName\n" +
243237
")";
244238

245-
Map<String, Object> params = new HashMap<>();
246-
params.put("name", name);
247-
params.put("surname", surname);
248-
params.put("email", email);
249-
params.put("salary", salary);
250-
params.put("departmentName", departmentName);
251-
params.put("companyName", companyName);
239+
240+
MapSqlParameterSource params = new MapSqlParameterSource()
241+
.addValue("name", name)
242+
.addValue("surname", surname)
243+
.addValue("email", email)
244+
.addValue("salary", salary)
245+
.addValue("departmentName", departmentName)
246+
.addValue("companyName", companyName);
252247

253248
RowMapper<RegisterEmployeeOutput> mapper = (rs, rowNum) -> {
254249
RegisterEmployeeOutput row = new RegisterEmployeeOutput();
@@ -263,8 +258,8 @@ public RegisterEmployeeOutput callRegisterEmployee(String name, String surname,
263258

264259
@Override
265260
public Integer getProjectsCount() {
266-
String query = "SELECT count(*) from project";
267-
return jdbcTemplate.queryForObject(query, (SqlParameterSource) null, Integer.class);
261+
String query = "SELECT count(*) FROM project";
262+
return jdbcTemplate.getJdbcOperations().queryForObject(query, Integer.class);
268263
}
269264

270265
@Override
@@ -274,10 +269,10 @@ public List<Department> findDepartmentsOfCompany(Company company) {
274269
" WHERE company_pid = :pid" +
275270
" ORDER BY pid";
276271

277-
Map<String, Object> params = new HashMap<>();
278-
params.put("pid", company.getPid());
272+
MapSqlParameterSource params = new MapSqlParameterSource()
273+
.addValue("pid", company.getPid());
279274

280-
return jdbcTemplate.query(query, params, new BeanPropertyRowMapper<>(Department.class));
275+
return jdbcTemplate.query(query, params, BeanPropertyRowMapper.newInstance(Department.class));
281276
}
282277

283278
@Override
@@ -286,10 +281,10 @@ public void deleteDepartments(List<Department> departmentsToDelete) {
286281
.map(Department::getPid)
287282
.collect(Collectors.toList());
288283

289-
Map<String, Object> params = new HashMap<>();
290-
params.put("pids", ids);
284+
MapSqlParameterSource params = new MapSqlParameterSource()
285+
.addValue("pids", ids);
291286

292-
String updateStatement = "DELETE FROM department where pid IN (:pids)";
287+
String updateStatement = "DELETE FROM department WHERE pid IN (:pids)";
293288

294289
jdbcTemplate.update(updateStatement, params);
295290
}
@@ -314,16 +309,28 @@ public void insertDepartments(List<Department> departmentsToInsert) {
314309
batchUpdateDepartments(departmentsToInsert, insertStatement);
315310
}
316311

312+
@Override
313+
public Project findProject(Integer pid) {
314+
String query;
315+
query = "SELECT pid, name, datestarted AS date" +
316+
" FROM project " +
317+
" WHERE pid = :pid";
318+
319+
MapSqlParameterSource params = new MapSqlParameterSource()
320+
.addValue("pid", pid);
321+
322+
// using BeanPropertyRowMapper is easier, but with much worse performance than custom RowMapper
323+
return jdbcTemplate.queryForObject(query, params, BeanPropertyRowMapper.newInstance(Project.class));
324+
}
325+
317326
private void batchUpdateDepartments(List<Department> departmentsToInsert, String statement) {
318327
MapSqlParameterSource[] paramsList = departmentsToInsert
319328
.stream()
320-
.map(department -> {
321-
MapSqlParameterSource params = new MapSqlParameterSource();
322-
params.addValue("pid", department.getPid());
323-
params.addValue("company_pid", department.getCompanyPid());
324-
params.addValue("name", department.getName());
325-
return params;
326-
})
329+
.map(department -> new MapSqlParameterSource()
330+
.addValue("pid", department.getPid())
331+
.addValue("company_pid", department.getCompanyPid())
332+
.addValue("name", department.getName())
333+
)
327334
.toArray(MapSqlParameterSource[]::new);
328335

329336
jdbcTemplate.batchUpdate(statement, paramsList);

src/main/java/com/clevergang/dbtests/repository/impl/jooq/JooqDataRepositoryImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,5 +329,18 @@ public void insertDepartments(List<Department> departmentsToInsert) {
329329
batch.execute();
330330
}
331331

332+
@Override
333+
public Project findProject(Integer pid) {
334+
return create.selectFrom(PROJECT)
335+
.where(PROJECT.PID.eq(pid))
336+
.fetchOne(project -> {
337+
Project result = new Project();
338+
result.setPid(project.getPid());
339+
result.setName(project.getName());
340+
result.setDate(project.getDatestarted().toLocalDate());
341+
return result;
342+
});
343+
}
344+
332345
}
333346

src/main/java/com/clevergang/dbtests/repository/impl/mybatis/DataRepositoryMapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ public interface DataRepositoryMapper {
4242
Integer getProjectsCount();
4343

4444
Employee findEmployee(Integer pid);
45+
46+
Project findProject(Integer pid);
4547
}

src/main/java/com/clevergang/dbtests/repository/impl/mybatis/MyBatisDataRepositoryImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public void insertDepartments(List<Department> departmentsToInsert) {
7979
batchOperations.flushStatements();
8080
}
8181

82+
@Override
83+
public Project findProject(Integer pid) {
84+
return sql.findProject(pid);
85+
}
86+
8287
@Override
8388
public Integer insertProject(Project project) {
8489
sql.insertProject(project);

src/main/resources/mybatis/mappers/DataRepositoryMapper.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,11 @@
128128
WHERE pid = #{pid}
129129
</select>
130130

131+
<select id="findProject" resultType="com.clevergang.dbtests.repository.api.data.Project">
132+
SELECT pid, name, datestarted as date
133+
FROM project
134+
WHERE pid = #{pid}
135+
</select>
136+
137+
131138
</mapper>

0 commit comments

Comments
 (0)