域模型
public class Vehicle {
private String vehicleNo;
private String color;
private int wheel;
private int seat;
// Constructors, Getters and Setters
...
}
表
CREATE TABLE VEHICLE (
VEHICLE_NO VARCHAR(10) NOT NULL,
COLOR VARCHAR(10),
WHEEL INT,
SEAT INT,
PRIMARY KEY (VEHICLE_NO)
);
DAO
public interface VehicleDao {
public void insert(Vehicle vehicle);
public void update(Vehicle vehicle);
public void delete(Vehicle vehicle);
public Vehicle findByVehicleNo(String vehicleNo);
}
Most parts of the JDBC APIs declare throwing java.sql.SQLException. But because this interface
aims to abstract the data access operations only, it should not depend on the implementation
technology. So, it’s unwise for this general interface to declare throwing the JDBC-specific SQLException.
A common practice when implementing a DAO interface is to wrap this kind of exception with a runtime
exception (either your own business Exception subclass or a generic one).
大部分 JDBC API声明抛出 SQLException异常, 但是对于DAO接口 它的目的仅仅是数据操作,所以针对拥有泛化性的接口来讲声明抛出JDBC规范的SQLException异常是不明智的。当实现DAO接口的时候 一种普遍的做法就是把这样类型的异常与RuntimeException异常包装在一起。
DAO实现类
public class JdbcVehicleDao implements VehicleDao {
private DataSource dataSource;
CHAPTER 15 ■ DATA ACCESS
601
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Vehicle vehicle) {
String sql = "INSERT INTO VEHICLE (VEHICLE_NO, COLOR, WHEEL, SEAT) "
+ "VALUES (?, ?, ?, ?)";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, vehicle.getVehicleNo());
ps.setString(2, vehicle.getColor());
ps.setInt(3, vehicle.getWheel());
ps.setInt(4, vehicle.getSeat());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
public Vehicle findByVehicleNo(String vehicleNo) {
String sql = "SELECT * FROM VEHICLE WHERE VEHICLE_NO = ?";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, vehicleNo);
Vehicle vehicle = null;
ResultSet rs = ps.executeQuery();
if (rs.next()) {
vehicle = new Vehicle(rs.getString("VEHICLE_NO"),
rs.getString("COLOR"), rs.getInt("WHEEL"),
rs.getInt("SEAT"));
}
rs.close();
ps.close();
return vehicle;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
CHAPTER 15 ■ DATA ACCESS
602
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
public void update(Vehicle vehicle) {/* … */}
public void delete(Vehicle vehicle) {/* … */}
}
in JDBC 2.0 or higher, you can obtain database connections from a
preconfigured javax.sql.DataSource object without knowing about the connection details.
在JDBC2.0或更高的版本里,我们可以在不知道任何关于连接的详细信息的情况下从预设值好的javax.sql.DataSource里获得数据库连接.
The vehicle insert operation is a typical JDBC update scenario. Each time this method is called, you
obtain a connection from the data source and execute the SQL statement on this connection. Your DAO
interface doesn’t declare throwing any checked exceptions, so if a SQLException occurs, you have to wrap
it with an unchecked RuntimeException. Don’t forget to release the connection in the finally block. Failing to do so
may cause your application to run out of connections.
当执行这个方法的时候 我们从data source里获取connection 然后在该connection执行SQL语句。由于我们的Dao接口没有声明抛出任何checked异常 所以如果一个SQLException异常放生 我们需要将它与unchecked RuntimeException异常包装在一起。最后不要忘记在finally块里释放Connection,因为当操作失败时 程序会用完该connection 来达到释放connection的目的.
Spring datasource配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="org.apache.derby.jdbc.ClientDriver" />
<property name="url"
value="jdbc:derby://localhost:1527/vehicle;create=true" />
<property name="username" value="app" />
<property name="password" value="app" />
</bean>
<bean id="vehicleDao"
class="com.apress.springrecipes.vehicle.JdbcVehicleDao">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
The javax.sql.DataSource interface is a standard interface defined by the JDBC specification that
factories Connection instances. There are many data source implementations provided by different
vendors and projects: C3PO and Apache Commons DBCP are popular open source options, and most
applications servers will provide their own implementation. It is very easy to switch between different
data source implementations, because they implement the common DataSource interface. As a Java
application framework, Spring also provides several convenient but less powerful data source
implementations. The simplest one is DriverManagerDataSource, which opens a new connection every
time one is requested.
javax.sql.DataSource接口是JDBC规范定义的一个标准,有很多的来自于不同的组织和项目提供的datasource相关实现 例如CSP0和Apache Commons DBCP就是非常广泛使用的相关实现,在不同的实现之间进行切换是非常容易的 因为他们实现的都是DataSource接口。作为Java框架 Spring也同样提供了几个方便的 但是不够强大的DataSource实现,其中最简单的实现就是DriverManagerDataSource,当每次有一个请求时该实现总会开辟一个新的Connection.
DriverManagerDataSource is not an efficient data source implementation because it opens a new
connection for the client every time it’s requested. Another data source implementation provided by
Spring is SingleConnectionDataSource (a DriverManagerDataSource subclass). As its name indicates, this
maintains only a single connection that’s reused all the time and never closed. Obviously, it is not
suitable in a multithreaded environment.
DriverManagerDataSource 不是一个很有效的DataSource实现 因为针对客户端的每次请求总会开辟一个新的Connection,Spring提供的另一个DataSource实现是SingleConnectionDataSource(它是DriverManagerDataSource的子类),如同的它的名字 它只保持维护一个Connection,在整个运行期一直会重复使用并且一直都不会关闭,很显然它不适合用于多线程环境。
Spring’s own data source implementations are mainly used for testing purposes. However, many
production data source implementations support connection pooling. For example, the Database
Connection Pooling Services (DBCP) module of the Apache Commons Library has several data source
implementations that support connection pooling. Of these, BasicDataSource accepts the same
connection properties as DriverManagerDataSource and allows you to specify the initial connection size
and maximum active connections for the connection pool.
Spring提供的DataSource实现一般都是用来测试的, 然而有很多的DataSource实现都支持连接池;例如 Apache Commons Library的 Database Connection Pooling Services(DBCP)模块拥有几个支持连接池的Datasource实现;其中 BasicDataSource 接受与DriverManagerDataSource一样的连接参数 并且允许我们针对连接池指定initial connection的大小和active connections 的最大值
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="org.apache.derby.jdbc.ClientDriver" />
<property name="url"
value="jdbc:derby://localhost:1527/vehicle;create=true" />
<property name="username" value="app" />
<property name="password" value="app" />
<property name="initialSize" value="2" />
<property name="maxActive" value="5" />
</bean>