9
9
---
10
10
11
11
## Intent
12
+
12
13
Object provides an abstract interface to some type of database or other persistence mechanism.
13
14
14
15
## Explanation
15
16
16
17
Real world example
17
18
18
- > There's a set of customers that need to be persisted to database. Additionally we need the whole set of CRUD (create/read/update/delete) operations so we can operate on customers easily.
19
+ > There's a set of customers that need to be persisted to database. Additionally we need the whole
20
+ > set of CRUD (create/read/update/delete) operations so we can operate on customers easily.
19
21
20
22
In plain words
21
23
22
24
> DAO is an interface we provide over the base persistence mechanism.
23
25
24
26
Wikipedia says
25
27
26
- > In computer software, a data access object (DAO) is a pattern that provides an abstract interface to some type of database or other persistence mechanism.
28
+ > In computer software, a data access object (DAO) is a pattern that provides an abstract interface
29
+ > to some type of database or other persistence mechanism.
27
30
28
31
** Programmatic Example**
29
32
30
- Walking through our customers example, here's the basic Customer entity.
33
+ Walking through our customers example, here's the basic ` Customer ` entity.
31
34
32
35
``` java
33
36
public class Customer {
@@ -41,60 +44,13 @@ public class Customer {
41
44
this . firstName = firstName;
42
45
this . lastName = lastName;
43
46
}
44
-
45
- public int getId () {
46
- return id;
47
- }
48
-
49
- public void setId (final int id ) {
50
- this . id = id;
51
- }
52
-
53
- public String getFirstName () {
54
- return firstName;
55
- }
56
-
57
- public void setFirstName (final String firstName ) {
58
- this . firstName = firstName;
59
- }
60
-
61
- public String getLastName () {
62
- return lastName;
63
- }
64
-
65
- public void setLastName (final String lastName ) {
66
- this . lastName = lastName;
67
- }
68
-
69
- @Override
70
- public String toString () {
71
- return " Customer{" + " id=" + getId() + " , firstName='" + getFirstName() + ' \' ' + " , lastName='"
72
- + getLastName() + ' \' ' + ' }' ;
73
- }
74
-
75
- @Override
76
- public boolean equals (final Object that ) {
77
- var isEqual = false ;
78
- if (this == that) {
79
- isEqual = true ;
80
- } else if (that != null && getClass() == that. getClass()) {
81
- final var customer = (Customer ) that;
82
- if (getId() == customer. getId()) {
83
- isEqual = true ;
84
- }
85
- }
86
- return isEqual;
87
- }
88
-
89
- @Override
90
- public int hashCode () {
91
- return getId();
92
- }
47
+ // getters and setters ->
48
+ ...
93
49
}
94
50
```
95
51
96
- Here's the DAO interface and two different implementations for it. InMemoryCustomerDao keeps a simple map of customers
97
- in memory while DBCustomerDao is the real RDBMS implementation.
52
+ Here's the ` CustomerDao ` interface and two different implementations for it. ` InMemoryCustomerDao `
53
+ keeps a simple map of customers in memory while ` DBCustomerDao ` is the real RDBMS implementation.
98
54
99
55
``` java
100
56
public interface CustomerDao {
@@ -114,35 +70,8 @@ public class InMemoryCustomerDao implements CustomerDao {
114
70
115
71
private final Map<Integer , Customer > idToCustomer = new HashMap<> ();
116
72
117
- @Override
118
- public Stream<Customer > getAll () {
119
- return idToCustomer. values(). stream();
120
- }
121
-
122
- @Override
123
- public Optional<Customer > getById (final int id ) {
124
- return Optional . ofNullable(idToCustomer. get(id));
125
- }
126
-
127
- @Override
128
- public boolean add (final Customer customer ) {
129
- if (getById(customer. getId()). isPresent()) {
130
- return false ;
131
- }
132
-
133
- idToCustomer. put(customer. getId(), customer);
134
- return true ;
135
- }
136
-
137
- @Override
138
- public boolean update (final Customer customer ) {
139
- return idToCustomer. replace(customer. getId(), customer) != null ;
140
- }
141
-
142
- @Override
143
- public boolean delete (final Customer customer ) {
144
- return idToCustomer. remove(customer. getId()) != null ;
145
- }
73
+ // implement the interface using the map
74
+ ...
146
75
}
147
76
148
77
public class DbCustomerDao implements CustomerDao {
@@ -155,121 +84,8 @@ public class DbCustomerDao implements CustomerDao {
155
84
this . dataSource = dataSource;
156
85
}
157
86
158
- @Override
159
- public Stream<Customer > getAll () throws Exception {
160
- try {
161
- var connection = getConnection();
162
- var statement = connection. prepareStatement(" SELECT * FROM CUSTOMERS" );
163
- var resultSet = statement. executeQuery();
164
- return StreamSupport . stream(new Spliterators .AbstractSpliterator<Customer > (Long . MAX_VALUE ,
165
- Spliterator . ORDERED ) {
166
-
167
- @Override
168
- public boolean tryAdvance (Consumer<? super Customer > action ) {
169
- try {
170
- if (! resultSet. next()) {
171
- return false ;
172
- }
173
- action. accept(createCustomer(resultSet));
174
- return true ;
175
- } catch (SQLException e) {
176
- throw new RuntimeException (e);
177
- }
178
- }
179
- }, false ). onClose(() - > mutedClose(connection, statement, resultSet));
180
- } catch (SQLException e) {
181
- throw new CustomException (e. getMessage(), e);
182
- }
183
- }
184
-
185
- private Connection getConnection () throws SQLException {
186
- return dataSource. getConnection();
187
- }
188
-
189
- private void mutedClose (Connection connection , PreparedStatement statement , ResultSet resultSet ) {
190
- try {
191
- resultSet. close();
192
- statement. close();
193
- connection. close();
194
- } catch (SQLException e) {
195
- LOGGER . info(" Exception thrown " + e. getMessage());
196
- }
197
- }
198
-
199
- private Customer createCustomer (ResultSet resultSet ) throws SQLException {
200
- return new Customer (resultSet. getInt(" ID" ),
201
- resultSet. getString(" FNAME" ),
202
- resultSet. getString(" LNAME" ));
203
- }
204
-
205
- @Override
206
- public Optional<Customer > getById (int id ) throws Exception {
207
-
208
- ResultSet resultSet = null ;
209
-
210
- try (var connection = getConnection();
211
- var statement = connection. prepareStatement(" SELECT * FROM CUSTOMERS WHERE ID = ?" )) {
212
-
213
- statement. setInt(1 , id);
214
- resultSet = statement. executeQuery();
215
- if (resultSet. next()) {
216
- return Optional . of(createCustomer(resultSet));
217
- } else {
218
- return Optional . empty();
219
- }
220
- } catch (SQLException ex) {
221
- throw new CustomException (ex. getMessage(), ex);
222
- } finally {
223
- if (resultSet != null ) {
224
- resultSet. close();
225
- }
226
- }
227
- }
228
-
229
- @Override
230
- public boolean add (Customer customer ) throws Exception {
231
- if (getById(customer. getId()). isPresent()) {
232
- return false ;
233
- }
234
-
235
- try (var connection = getConnection();
236
- var statement = connection. prepareStatement(" INSERT INTO CUSTOMERS VALUES (?,?,?)" )) {
237
- statement. setInt(1 , customer. getId());
238
- statement. setString(2 , customer. getFirstName());
239
- statement. setString(3 , customer. getLastName());
240
- statement. execute();
241
- return true ;
242
- } catch (SQLException ex) {
243
- throw new CustomException (ex. getMessage(), ex);
244
- }
245
- }
246
-
247
- @Override
248
- public boolean update (Customer customer ) throws Exception {
249
- try (var connection = getConnection();
250
- var statement =
251
- connection
252
- .prepareStatement(" UPDATE CUSTOMERS SET FNAME = ?, LNAME = ? WHERE ID = ?" )) {
253
- statement. setString(1 , customer. getFirstName());
254
- statement. setString(2 , customer. getLastName());
255
- statement. setInt(3 , customer. getId());
256
- return statement. executeUpdate() > 0 ;
257
- } catch (SQLException ex) {
258
- throw new CustomException (ex. getMessage(), ex);
259
- }
260
- }
261
-
262
- @Override
263
- public boolean delete (Customer customer ) throws Exception {
264
- try (var connection = getConnection();
265
- var statement = connection. prepareStatement(" DELETE FROM CUSTOMERS WHERE ID = ?" )) {
266
- statement. setInt(1 , customer. getId());
267
- return statement. executeUpdate() > 0 ;
268
- } catch (SQLException ex) {
269
- throw new CustomException (ex. getMessage(), ex);
270
- }
271
- }
272
- }
87
+ // implement the interface using the data source
88
+ ...
273
89
```
274
90
275
91
Finally here' s how we use our DAO to manage customers.
@@ -301,15 +117,45 @@ Finally here's how we use our DAO to manage customers.
301
117
deleteSchema(dataSource);
302
118
```
303
119
120
+ The program output:
121
+
122
+ ```java
123
+ customerDao.getAllCustomers():
124
+ Customer{id=1, firstName=' Adam ' , lastName=' Adamson ' }
125
+ Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }
126
+ Customer{id=3, firstName=' Carl ' , lastName=' Carlson ' }
127
+ customerDao.getCustomerById(2): Optional[Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }]
128
+ customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@7cef4e59
129
+ customerDao.getAllCustomers():
130
+ Customer{id=1, firstName=' Adam ' , lastName=' Adamson ' }
131
+ Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }
132
+ Customer{id=3, firstName=' Carl ' , lastName=' Carlson ' }
133
+ Customer{id=4, firstName=' Daniel ' , lastName=' Danielson ' }
134
+ customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@2db0f6b2
135
+ customerDao.getAllCustomers():
136
+ Customer{id=1, firstName=' Adam ' , lastName=' Adamson ' }
137
+ Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }
138
+ Customer{id=3, firstName=' Carl ' , lastName=' Carlson ' }
139
+ customerDao.getCustomerById(2): Optional[Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }]
140
+ customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@12c8a2c0
141
+ customerDao.getAllCustomers():
142
+ Customer{id=1, firstName=' Adam ' , lastName=' Adamson ' }
143
+ Customer{id=2, firstName=' Bob ' , lastName=' Bobson ' }
144
+ Customer{id=3, firstName=' Carl ' , lastName=' Carlson ' }
145
+ Customer{id=4, firstName=' Daniel ' , lastName=' Danielson ' }
146
+ customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@6ec8211c
147
+ ```
304
148
305
149
## Class diagram
150
+
306
151

307
152
308
153
## Applicability
309
- Use the Data Access Object in any of the following situations
310
154
311
- * when you want to consolidate how the data layer is accessed
312
- * when you want to avoid writing multiple data retrieval/persistence layers
155
+ Use the Data Access Object in any of the following situations:
156
+
157
+ * When you want to consolidate how the data layer is accessed.
158
+ * When you want to avoid writing multiple data retrieval/persistence layers.
313
159
314
160
## Credits
315
161
0 commit comments