99---
1010
1111## Intent
12+
1213Object provides an abstract interface to some type of database or other persistence mechanism.
1314
1415## Explanation
1516
1617Real world example
1718
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.
1921
2022In plain words
2123
2224> DAO is an interface we provide over the base persistence mechanism.
2325
2426Wikipedia says
2527
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.
2730
2831** Programmatic Example**
2932
30- Walking through our customers example, here's the basic Customer entity.
33+ Walking through our customers example, here's the basic ` Customer ` entity.
3134
3235``` java
3336public class Customer {
@@ -41,60 +44,13 @@ public class Customer {
4144 this . firstName = firstName;
4245 this . lastName = lastName;
4346 }
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+ ...
9349}
9450```
9551
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.
9854
9955``` java
10056public interface CustomerDao {
@@ -114,35 +70,8 @@ public class InMemoryCustomerDao implements CustomerDao {
11470
11571 private final Map<Integer , Customer > idToCustomer = new HashMap<> ();
11672
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+ ...
14675}
14776
14877public class DbCustomerDao implements CustomerDao {
@@ -155,121 +84,8 @@ public class DbCustomerDao implements CustomerDao {
15584 this . dataSource = dataSource;
15685 }
15786
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+ ...
27389```
27490
27591Finally 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.
301117 deleteSchema(dataSource);
302118```
303119
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+ ```
304148
305149## Class diagram
150+
306151
307152
308153## Applicability
309- Use the Data Access Object in any of the following situations
310154
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.
313159
314160## Credits
315161
0 commit comments