下面是数据库持久层的一个样例:
首先,国际惯例.据说是为了支持多数据库.来个接口.
package db;
import bus.Product;
import java.util.List;
public interface ProductManagerDao {
public List getProductList();
public void increasePrice(Product prod, int pct);
}
下面是一个jdbc的实现 .
package db;
import bus.Product;
import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlUpdate;
import org.springframework.jdbc.core.SqlParameter;
public class ProductManagerDaoJdbc implements ProductManagerDao {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private DataSource ds;
public List getProductList() {
logger.info("Getting products!");
ProductQuery pq = new ProductQuery(ds);
return pq.execute();
}
public void increasePrice(Product prod, int pct) {
logger.info("Increasing price by " + pct + "%");
SqlUpdate su =
new SqlUpdate(ds, "update products set price = price * (100 + ?) / 100 where id = ?");
su.declareParameter(new SqlParameter("increase", Types.INTEGER));
su.declareParameter(new SqlParameter("ID", Types.INTEGER));
su.compile();
Object[] oa = new Object[2];
oa[0] = new Integer(pct);
oa[1] = new Integer(prod.getId());
int count = su.update(oa);
logger.info("Rows affected: " + count);
}
public void setDataSource(DataSource ds) {
this.ds = ds;
}
class ProductQuery extends MappingSqlQuery {
ProductQuery(DataSource ds) {
super(ds, "SELECT id, description, price from products");
compile();
}
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Product prod = new Product();
prod.setId(rs.getInt("id"));
prod.setDescription(rs.getString("description"));
prod.setPrice(new Double(rs.getDouble("price")));
return prod;
}
}
}
对于上面的类的解释,还是来看看原文:
Lets go over the two DAO methods in this class. First, getProductList() creates a query object that will retrieve all the products. This query is executed and the results are passed back as a list of Products. At the end of the class we can see the definition for this query class. I have implemented it as an inner class since we are not going to reference it anywhere else, but I could just as well have made it a separate class. This query class extends MappingSqlQuery, which is a central class in Spring's JDBC framework. The idea behind this class is that you have to specify a SQL query when this class is created, and you are also responsible for implementing the mapRow method to map the data from each row into a class that represents the entity you are retrieving in your query. That's it, that's all you have to provide. The rest is managed by the framework. In the constructor of the ProductQuery class I pass in the data source. This data source will be provided in a similar fashion to the way we wired up the business objects in Part 2, so we don't have to worry about retrieving a data source in our DAO class. In the constructor I also define the SQL query that we will use to retrieve the products. The mapRow method will be called once for each row returned by the query. It creates a new Product and populates it based on the data retrieved from the current row of the resultset. You should not call getNext on the resultset, it is all handled by the framework. This is another example of an Inversion of Control solution.
The second method increasePrice is utilizing an SqlUpdate class. This class is passed the data source and an SQL update statement with placeholders for parameters. Same syntax as a prepared statement in JDBC. In fact, that is what SqlUpdate creates behind the scenes. For the parameters, we have to give them a name and declare what type they are so that the framework can set them before the prepared statement is executed. After all parameters have been declared, we “compile?? the statement in JDO fashion. This will signal that we are done declaring parameters, and the framework will check to make sure that we have a matching declaration for each placeholder in the SQL statement. Next we declare an Object array that will hold the parameter values that we are going to pass in to the prepared statement. This array gets passed into the update method of SqlUpdate. The update method does return the count of rows affected.
ProductManager.java改动如下所示:
package bus;
import java.io.Serializable;
import java.util.ListIterator;
import java.util.List;
import db.ProductManagerDao;
public class ProductManager implements Serializable {
private ProductManagerDao pmd;
private List products;
public void setProductManagerDao(ProductManagerDao pmd) {
this.pmd = pmd;
}
/*
public void setProducts(List p) {
products = p;
}
*/
public List getProducts() {
products = pmd.getProductList();
return products;
}
public void increasePrice(int pct) {
ListIterator li = products.listIterator();
while (li.hasNext()) {
Product p = (Product) li.next();
/*
double newPrice = p.getPrice().doubleValue() * (100 + pct)/100;
p.setPrice(new Double(newPrice));
*/
pmd.increasePrice(p, pct);
}
}
}
这样的话,在springapp-servlet.xml中也修改做相应的主入修改
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
<property name="url">
<value>jdbc:hsqldb:/home/trisberg/workspace/springapp/db/test</value>
</property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>
</bean>
<bean id="prodManDao" class="db.ProductManagerDaoJdbc">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="prodMan" class="bus.ProductManager">
<property name="productManagerDao">
<ref bean="prodManDao"/>
</property>
</bean>
整个文件之间的调用关系就结束了。可以看到真实的类和类之间的关系基本是用配置文件关联起来的,在java文件里面只有
接口的关系。