@@ -3,7 +3,10 @@ title: Data Access Object
3
3
category : Structural
4
4
language : en
5
5
tag :
6
+ - Abstraction
6
7
- Data access
8
+ - Data processing
9
+ - Decoupling
7
10
- Layered architecture
8
11
- Persistence
9
12
---
@@ -21,7 +24,7 @@ The Data Access Object (DAO) design pattern aims to separate the application's b
21
24
22
25
Real world example
23
26
24
- > 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 .
27
+ > Imagine a library system where the main application manages book loans, user accounts, and inventory. The Data Access Object (DAO) pattern in this context would be used to separate the database operations (such as fetching book details, updating user records, and checking inventory) from the business logic of managing loans and accounts. For instance, there would be a ` BookDAO ` class responsible for all database interactions related to books, such as retrieving a book by its ISBN or updating its availability status. This abstraction allows the library system's main application code to focus on business rules and workflows, while the ` BookDAO ` handles the complex SQL queries and data management. This separation makes the system easier to maintain and test, as changes to the data source or business logic can be managed independently .
25
28
26
29
In plain words
27
30
@@ -33,20 +36,22 @@ Wikipedia says
33
36
34
37
** Programmatic Example**
35
38
39
+ 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.
40
+
36
41
Walking through our customers example, here's the basic ` Customer ` entity.
37
42
38
43
``` java
44
+ @Setter
45
+ @Getter
46
+ @ToString
47
+ @EqualsAndHashCode (onlyExplicitlyIncluded = true )
48
+ @AllArgsConstructor
39
49
public class Customer {
40
50
51
+ @EqualsAndHashCode . Include
41
52
private int id;
42
53
private String firstName;
43
54
private String lastName;
44
-
45
- public Customer (int id , String firstName , String lastName ) {
46
- this . id = id;
47
- this . firstName = firstName;
48
- this . lastName = lastName;
49
- }
50
55
}
51
56
```
52
57
@@ -74,16 +79,10 @@ public class InMemoryCustomerDao implements CustomerDao {
74
79
}
75
80
76
81
@Slf4j
82
+ @RequiredArgsConstructor
77
83
public class DbCustomerDao implements CustomerDao {
78
84
79
- private final DataSource
80
- dataSource;
81
-
82
- public DbCustomerDao (
83
- DataSource dataSource ) {
84
- this . dataSource =
85
- dataSource;
86
- }
85
+ private final DataSource dataSource;
87
86
88
87
// implement the interface using the data source
89
88
}
@@ -92,64 +91,111 @@ public class DbCustomerDao implements CustomerDao {
92
91
Finally, here's how we use our DAO to manage customers.
93
92
94
93
``` java
95
- final var dataSource= createDataSource();
94
+
95
+ @Slf4j
96
+ public class App {
97
+ private static final String DB_URL = " jdbc:h2:mem:dao;DB_CLOSE_DELAY=-1" ;
98
+ private static final String ALL_CUSTOMERS = " customerDao.getAllCustomers(): " ;
99
+
100
+ public static void main (final String [] args ) throws Exception {
101
+ final var inMemoryDao = new InMemoryCustomerDao ();
102
+ performOperationsUsing(inMemoryDao);
103
+
104
+ final var dataSource = createDataSource();
96
105
createSchema(dataSource);
97
- final var customerDao= new DbCustomerDao (dataSource);
106
+ final var dbDao = new DbCustomerDao (dataSource);
107
+ performOperationsUsing(dbDao);
108
+ deleteSchema(dataSource);
109
+ }
110
+
111
+ private static void deleteSchema (DataSource dataSource ) throws SQLException {
112
+ try (var connection = dataSource. getConnection();
113
+ var statement = connection. createStatement()) {
114
+ statement. execute(CustomerSchemaSql . DELETE_SCHEMA_SQL );
115
+ }
116
+ }
98
117
118
+ private static void createSchema (DataSource dataSource ) throws SQLException {
119
+ try (var connection = dataSource. getConnection();
120
+ var statement = connection. createStatement()) {
121
+ statement. execute(CustomerSchemaSql . CREATE_SCHEMA_SQL );
122
+ }
123
+ }
124
+
125
+ private static DataSource createDataSource () {
126
+ var dataSource = new JdbcDataSource ();
127
+ dataSource. setURL(DB_URL );
128
+ return dataSource;
129
+ }
130
+
131
+ private static void performOperationsUsing (final CustomerDao customerDao ) throws Exception {
99
132
addCustomers(customerDao);
100
- log . info(ALL_CUSTOMERS );
101
- try (var customerStream= customerDao. getAll()){
102
- customerStream. forEach(( customer) - > log . info(customer. toString()));
133
+ LOGGER . info(ALL_CUSTOMERS );
134
+ try (var customerStream = customerDao. getAll()) {
135
+ customerStream. forEach(customer - > LOGGER . info(customer. toString()));
103
136
}
104
- log . info(" customerDao.getCustomerById(2): " + customerDao. getById(2 ));
105
- final var customer= new Customer (4 ," Dan" ," Danson" );
137
+ LOGGER . info(" customerDao.getCustomerById(2): " + customerDao. getById(2 ));
138
+ final var customer = new Customer (4 , " Dan" , " Danson" );
106
139
customerDao. add(customer);
107
- log . info(ALL_CUSTOMERS + customerDao. getAll());
140
+ LOGGER . info(ALL_CUSTOMERS + customerDao. getAll());
108
141
customer. setFirstName(" Daniel" );
109
142
customer. setLastName(" Danielson" );
110
143
customerDao. update(customer);
111
- log . info(ALL_CUSTOMERS );
112
- try (var customerStream= customerDao. getAll()){
113
- customerStream. forEach(( cust) - > log . info(cust. toString()));
144
+ LOGGER . info(ALL_CUSTOMERS );
145
+ try (var customerStream = customerDao. getAll()) {
146
+ customerStream. forEach(cust - > LOGGER . info(cust. toString()));
114
147
}
115
148
customerDao. delete(customer);
116
- log. info(ALL_CUSTOMERS + customerDao. getAll());
149
+ LOGGER . info(ALL_CUSTOMERS + customerDao. getAll());
150
+ }
117
151
118
- deleteSchema(dataSource);
152
+ private static void addCustomers (CustomerDao customerDao ) throws Exception {
153
+ for (var customer : generateSampleCustomers()) {
154
+ customerDao. add(customer);
155
+ }
156
+ }
157
+
158
+ public static List<Customer > generateSampleCustomers () {
159
+ final var customer1 = new Customer (1 , " Adam" , " Adamson" );
160
+ final var customer2 = new Customer (2 , " Bob" , " Bobson" );
161
+ final var customer3 = new Customer (3 , " Carl" , " Carlson" );
162
+ return List . of(customer1, customer2, customer3);
163
+ }
164
+ }
119
165
```
120
166
121
167
The program output:
122
168
123
- ``` java
124
- customerDao. getAllCustomers():
125
- Customer { id= 1 ,firstName= ' Adam' , lastName= ' Adamson' }
126
- Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' }
127
- Customer { id= 3 ,firstName= ' Carl' , lastName= ' Carlson' }
128
- customerDao. getCustomerById(2 ): Optional [Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' } ]
129
- customerDao. getAllCustomers(): java.util.stream. ReferencePipeline $Head @7cef4e59
130
- customerDao. getAllCustomers():
131
- Customer { id= 1 ,firstName= ' Adam' , lastName= ' Adamson' }
132
- Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' }
133
- Customer { id= 3 ,firstName= ' Carl' , lastName= ' Carlson' }
134
- Customer { id= 4 ,firstName= ' Daniel' , lastName= ' Danielson' }
135
- customerDao. getAllCustomers(): java.util.stream. ReferencePipeline $Head @2db0f6b2
136
- customerDao. getAllCustomers():
137
- Customer { id= 1 ,firstName= ' Adam' , lastName= ' Adamson' }
138
- Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' }
139
- Customer { id= 3 ,firstName= ' Carl' , lastName= ' Carlson' }
140
- customerDao. getCustomerById(2 ): Optional [Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' } ]
141
- customerDao. getAllCustomers(): java.util.stream. ReferencePipeline $Head @12c8a2c0
142
- customerDao. getAllCustomers():
143
- Customer { id= 1 ,firstName= ' Adam' , lastName= ' Adamson' }
144
- Customer { id= 2 ,firstName= ' Bob' , lastName= ' Bobson' }
145
- Customer { id= 3 ,firstName= ' Carl' , lastName= ' Carlson' }
146
- Customer { id= 4 ,firstName= ' Daniel' , lastName= ' Danielson' }
147
- customerDao. getAllCustomers(): java.util.stream. ReferencePipeline $Head @6ec8211c
169
+ ```
170
+ 10:02:09.788 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers():
171
+ 10:02:09.793 [main] INFO com.iluwatar.dao.App -- Customer( id=1, firstName=Adam, lastName=Adamson)
172
+ 10:02:09.793 [main] INFO com.iluwatar.dao.App -- Customer( id=2, firstName=Bob, lastName=Bobson)
173
+ 10:02:09.793 [main] INFO com.iluwatar.dao.App -- Customer( id=3, firstName=Carl, lastName=Carlson)
174
+ 10:02:09.794 [main] INFO com.iluwatar.dao.App -- customerDao.getCustomerById(2): Optional[Customer( id=2, firstName=Bob, lastName=Bobson) ]
175
+ 10:02:09.794 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@4c3e4790
176
+ 10:02:09.794 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers():
177
+ 10:02:09.795 [main] INFO com.iluwatar.dao.App -- Customer( id=1, firstName=Adam, lastName=Adamson)
178
+ 10:02:09.795 [main] INFO com.iluwatar.dao.App -- Customer( id=2, firstName=Bob, lastName=Bobson)
179
+ 10:02:09.795 [main] INFO com.iluwatar.dao.App -- Customer( id=3, firstName=Carl, lastName=Carlson)
180
+ 10:02:09.795 [main] INFO com.iluwatar.dao.App -- Customer( id=4, firstName=Daniel, lastName=Danielson)
181
+ 10:02:09.795 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@5679c6c6
182
+ 10:02:09.894 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers():
183
+ 10:02:09.895 [main] INFO com.iluwatar.dao.App -- Customer( id=1, firstName=Adam, lastName=Adamson)
184
+ 10:02:09.895 [main] INFO com.iluwatar.dao.App -- Customer( id=2, firstName=Bob, lastName=Bobson)
185
+ 10:02:09.895 [main] INFO com.iluwatar.dao.App -- Customer( id=3, firstName=Carl, lastName=Carlson)
186
+ 10:02:09.895 [main] INFO com.iluwatar.dao.App -- customerDao.getCustomerById(2): Optional[Customer( id=2, firstName=Bob, lastName=Bobson) ]
187
+ 10:02:09.896 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@23282c25
188
+ 10:02:09.897 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers():
189
+ 10:02:09.897 [main] INFO com.iluwatar.dao.App -- Customer( id=1, firstName=Adam, lastName=Adamson)
190
+ 10:02:09.897 [main] INFO com.iluwatar.dao.App -- Customer( id=2, firstName=Bob, lastName=Bobson)
191
+ 10:02:09.898 [main] INFO com.iluwatar.dao.App -- Customer( id=3, firstName=Carl, lastName=Carlson)
192
+ 10:02:09.898 [main] INFO com.iluwatar.dao.App -- Customer( id=4, firstName=Daniel, lastName=Danielson)
193
+ 10:02:09.898 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@f2f2cc1
148
194
```
149
195
150
196
## Class diagram
151
197
152
- ![ alt text ] ( ./etc/dao.png " Data Access Object ")
198
+ ![ Data Access Object ] ( ./etc/dao.png " Data Access Object ")
153
199
154
200
## Applicability
155
201
@@ -161,8 +207,8 @@ Use the Data Access Object in any of the following situations:
161
207
162
208
## Tutorials
163
209
164
- * [ The DAO Pattern in Java] ( https://www.baeldung.com/java-dao-pattern )
165
- * [ Data Access Object Pattern] ( https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm )
210
+ * [ The DAO Pattern in Java(Baeldung) ] ( https://www.baeldung.com/java-dao-pattern )
211
+ * [ Data Access Object Pattern (TutorialsPoint) ] ( https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm )
166
212
167
213
## Known Uses
168
214
@@ -187,15 +233,15 @@ Trade-offs:
187
233
188
234
## Related Patterns
189
235
190
- * [ Service Layer] ( https://java-design-patterns.com/patterns/service-layer/ ) : Often used in conjunction with the DAO pattern to define application's boundaries and its set of available operations.
191
- * [ Factory] ( https://java-design-patterns.com/patterns/factory/ ) : Can be used to instantiate DAOs dynamically, providing flexibility in the choice of implementation.
192
236
* [ Abstract Factory] ( https://java-design-patterns.com/patterns/abstract-factory/ ) : Helps in abstracting the creation of DAOs, especially when supporting multiple databases or storage mechanisms.
237
+ * [ Factory] ( https://java-design-patterns.com/patterns/factory/ ) : Can be used to instantiate DAOs dynamically, providing flexibility in the choice of implementation.
238
+ * [ Service Layer] ( https://java-design-patterns.com/patterns/service-layer/ ) : Often used in conjunction with the DAO pattern to define application's boundaries and its set of available operations.
193
239
* [ Strategy] ( https://java-design-patterns.com/patterns/strategy/ ) : Might be employed to change the data access strategy at runtime, depending on the context.
194
240
195
241
## Credits
196
242
197
- * [ J2EE Design Patterns] ( https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31 )
198
243
* [ Core J2EE Patterns: Best Practices and Design Strategies] ( https://amzn.to/49u3r91 )
199
- * [ Patterns of Enterprise Application Architecture] ( https://amzn.to/3U5cxEI )
200
244
* [ Expert One-on-One J2EE Design and Development] ( https://amzn.to/3vK3pfq )
245
+ * [ J2EE Design Patterns] ( https://amzn.to/4dpzgmx )
246
+ * [ Patterns of Enterprise Application Architecture] ( https://amzn.to/3U5cxEI )
201
247
* [ Professional Java Development with the Spring Framework] ( https://amzn.to/49tANF0 )
0 commit comments