One aspect of the business layer is the data access layer that connects the services with the database. Accessing data varies depending on the source of the data. Access to persistent data varies greatly depending on the type of storage (database, flat files, xml files, and so on) and it even differs from its implementation (for example different SQL-dialects).
The goal is to abstract and encapsulate all access to the data and provide an interface. This is called the Data Access Object pattern. In a nutshell, the DAO "knows" which data source (that could be a database, a flat file or even a WebService) to connect to and is specific for this data source (e.g. a OracleDAO might use oracle-specific data types, a WebServiceDAO might parse the incoming and outgoing message etc.).
From the applications point of view, it makes no difference when it accesses a relational database or parses xml files (using a DAO). The DAO is usually able to create an instance of a data object ("to read data") and also to persist data ("to save data") to the datasource.
To see the DAO pattern in action, look at the (heavily documented) class JdbcObjectStudentDAO in the basic example.
Use a Data Access Object when:
In the following example we will create a Data Access Object for saving/retrieving the data of books.
To keep the source-code simple, import declarations and exception-handling is not shown.
public interface BookDAO { public void saveBook(Book b); public Book loadBook(String isbn); }
The first implementation flavor will use a simple database (possibly remote) for storing the data:
public class DBBookDAO implements BookDAO { private PreparedStatement saveStmt; private PreparedStatement loadStmt; public DBBookDAO(String url, String user, String pw) { Connection con = DriverManager.getConnection(url, user, pw); saveStmt = con.prepareStatement("INSERT INTO books(isbn, title, author) " +"VALUES (?, ?, ?)"); loadStmt = con.prepareStatement("SELECT isbn, title, author FROM books " +"WHERE isbn = ?"); } public Book loadBook(String isbn) { Book b = new Book(); loadStmt.setString(1, isbn); ResultSet result = loadStmt.executeQuery(); if (!result.next()) return null; b.setIsbn(result.getString("isbn")); b.setTitle(result.getString("title")); b.setAuthor(result.getString("author")); return b; } public void saveBook(Book b) { saveStmt.setString(1, b.getIsbn()); saveStmt.setString(2, b.getTitle()); saveStmt.setString(3, b.getAuthor()); saveStmt.executeUpdate(); } }
The second implementation flavor saves every book in its own text-file on the local hard drive:
public class FileBookDAO implements BookDAO { private String basePath; public FileBookDAO(String basePath) { this.basePath = basePath; } public Book loadBook(String isbn) { FileReader fr = new FileReader(basePath + isbn); BufferedReader br = new BufferedReader(fr); Book b = new Book(); String rIsbn = br.readLine(); String rTitle = br.readLine(); String rAuthor = br.readLine(); if (rIsbn.startsWith("ISBN: ")) { b.setIsbn(rIsbn.substring("ISBN: ".length())); } else { return null; } if (rTitle.startsWith("TITLE: ")) { b.setTitle(rTitle.substring("TITLE: ".length())); } else { return null; } if (rAuthor.startsWith("AUTHOR: ")) { b.setAuthor(rAuthor.substring("AUTHOR: ".length())); } else { return null; } return b; } public void saveBook(Book b) { FileWriter fw = new FileWriter(basePath + b.getIsbn() + ".book"); fw.write("ISBN: " + b.getIsbn()); fw.write("TITLE: " + b.getTitle()); fw.write("AUTHOR: " + b.getAuthor()); fw.close(); } }