Skip to content

Commit 6373f7b

Browse files
committed
Update README.md
1 parent e8b42bd commit 6373f7b

File tree

1 file changed

+47
-201
lines changed

1 file changed

+47
-201
lines changed

dao/README.md

+47-201
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,28 @@ tags:
99
---
1010

1111
## Intent
12+
1213
Object provides an abstract interface to some type of database or other persistence mechanism.
1314

1415
## Explanation
1516

1617
Real 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
2022
In plain words
2123

2224
> DAO is an interface we provide over the base persistence mechanism.
2325
2426
Wikipedia 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
3336
public 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
10056
public 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

14877
public 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

27591
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.
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
![alt text](./etc/dao.png "Data Access Object")
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

Comments
 (0)