• Aucun résultat trouvé

DB Access in E-shop

Dans le document Beginning JSP, JSF and Tomcat (Page 187-191)

As I mentioned in Chapter 3, all database operations are concentrated in the data model of an MVC architecture. JSP modules interact with the database by executing methods of the DataManager class, which accept and/or return data in the form of Java beans. By mediating DB access via the data manager and Java beans, you ensure that the view and the model can be developed independently.

Figure 6-5 shows the structure of the model.

Data Manager

JSP

Model

Category Peer

Book Peer

DB Order

Peer

Order Details Peer

Figure 6-5. The data model structure

The DataManager class sets up and closes connections to the database; however, concerning table access, it only acts as a clearinghouse. Specific classes perform the actual operations on individual tables. In this way, you ensure that changes to individual tables have the minimum impact on the application. This is actually an example of the Java EnterPrise Edition pattern called Data Access Object (DAO).

For example, the JSP page that displays the book details obtains the information concerning the requested book by executing the following method of the data manager:

public Book getBookDetails(int bookID) { return BookPeer.getBookById(this, bookID);

}

It is the getBookByID method in BookPeer.java that performs the actual database access, as shown in Listing 6-10.

Listing 6-10. The BookPeer.getBookID Method

01: public static Book getBookById(DataManager dataManager, int bookID) { 02: Book book = null;

03: Connection connection = dataManager.getConnection();

04: if (connection != null) { 05: try {

06: Statement s = connection.createStatement();

07: String sql = "select book_id, title, author, price from books"

08: + " where book_id=" + bookID;

09: try {

22: System.out.println("Could not get book: " + e.getMessage());

23: } 24: finally {

25: dataManager.putConnection(connection);

26: }

27: } return book;

28: }

In line 3, you open the database connection by invoking a method of the data manager that also reports an error in case of failure. Then you start a try block where you do the actual work. In the corresponding catch block, you display an error message (line 22), and in the finally block (line 25), you close the DB connection. Remember that the finally block is executed whether the try succeeds or not.

In this way, you ensure that the connection is closed in case of failure.

Inside the outermost try (lines 5–20), you create a statement and set up the query string before starting a second try block (lines 9–17). Similar to what you did concerning the connection, you use the finally block to close the statement (line 19).

This is a technique of general applicability: every time you do something that needs to be undone, take care of it immediately inside a try block by placing the “undoing” statement in the corresponding finally. In this way, you’ll be sure not to leave any “ghosts” behind you. It’s true that Java’s garbage-collection mechanism should take care of removing unreferenced objects, but it’s good practice to clean up behind yourself as you go, especially when you’re dealing with databases and potentially large objects, such as statements and result sets. At the very least, your application will work more efficiently.

And it feels good to write “clean” code.

Line 10 is where you actually execute the query. You know that you’re not going to get more than one row in the result set, because the book_id is a unique key of the book table.

You might be thinking, “Why should I go through the data manager at all? Couldn’t I simply execute the BookPeer method from JSP?” Well, you could, but it wouldn’t be clean, and dirtiness sooner or later causes problems.

Furthermore, consider the more complex case in which you want to save an order. From the JSP point of view, you only want to call a method of the data manager that takes care of both the customer’s data and the shopping cart. Behind the scenes, though, two different tables need to be updated: one for the orders and one for the order details. Therefore, it makes a lot of sense to execute the overall

transaction in the data manager (see Listing 6-11) while leaving the updates of individual tables to the peer classes.

Listing 6-11. The DataManager.insertOrder Method

public long insertOrder(Customer customer, Hashtable shoppingCart) { long returnValue = 0L;

long orderId = System.currentTimeMillis();

Connection connection = getConnection();

if (connection != null) { Statement stmt = null;

try {

connection.setAutoCommit(false);

stmt = connection.createStatement();

try {

OrderPeer.insertOrder(stmt, orderId, customer);

OrderDetailsPeer.insertOrderDetails(stmt, orderId, shoppingCart);

try { stmt.close(); }

System.out.println("Could not insert order: " + e.getMessage());

try { connection.rollback(); } catch (SQLException ee) { } }

}

catch (SQLException e) {

System.out.println("Could not insert order: " + e.getMessage());

}

The two lines in bold show you how the data manager asks the peer classes of the tables orders and order_details to do the update. Notice that you pass to them the same statement and order ID. Listing 6-12 shows insertOrder, one of the two methods that do the updates.

Listing 6-12. The OrderPeer.insertOrder Method

public static void insertOrder(Statement stmt, long orderId, Customer customer) throws SQLException {

String sql = "insert into orders (order_id, delivery_name,"

+ " delivery_address, cc_name, cc_number, cc_expiry) values ('"

+ orderId + "','" + customer.getContactName() + "','"

+ customer.getDeliveryAddress() + "','"

+ customer.getCcName() + "','" + customer.getCcNumber() + "','" + customer.getCcExpiryDate() + "')"

;

stmt.executeUpdate(sql);

}

Listing 6-13 shows the other method, insertOrderDetails.

Listing 6-13. The OrderDetailsPeer.insertOrderDetails Method

public static void insertOrderDetails(Statement stmt, long orderId, Hashtable shoppingCart) throws SQLException {

String sql;

Enumeration enumList = shoppingCart.elements();

while (enumList.hasMoreElements()) {

CartItem item = (CartItem)enumList.nextElement();

sql = "insert into order_details (order_id, book_id, quantity,"

+ " price, title, author) values ('" + orderId + "','"

+ item.getBookID() + "','" + item.getQuantity() + "','"

+ item.getPrice() + "','" + item.getTitle() + "','"

+ item.getAuthor() + "')"

;

stmt.executeUpdate(sql);

} }

The methods throw the SQL exception rather than catch it locally, so that the data manager’s method catches it.

Dans le document Beginning JSP, JSF and Tomcat (Page 187-191)