20. 三层架构中的MVC Web应用程序——示例6,SQL Server Express
20.1. SQL Server Express 数据库
在此版本中,我们将把人员列表导入 SQL Server Express 2005 数据库表中,该表可通过网址 [http://msdn.microsoft.com/vstudio/express/sql/] 获取。 下文中的屏幕截图均来自 EMS Manager Lite 客户端(适用于 SQL Server Express [http://www.sqlmanager.net/fr/products/mssql/manager]), 这是 SGBD SQL Server Express 的免费管理客户端。
该数据库名为 [dbpersonnes]。其中包含一个名为 [PERSONNES] 的表:

表 [PERSONNES] 将包含由 Web 应用程序管理的人员列表。该表是通过以下 SQL 命令构建的:
- 第 2 行:主键 [ID] 的数据类型为整数。 属性 IDENTITY 表示,如果在表中插入一行且 ID 列为空,SQL Express 将自动为该列生成一个整数。 在 IDENTITY(1, 1) 中,第一个参数是主键的第一个可能值,第二个参数是生成数字时使用的增量。
表 [PERSONNES] 的内容可能如下:

我们知道,当通过我们的 [dao] 层插入 [Personne] 对象时, 该对象的 [id] 字段在插入前等于 -1,插入后则取一个不同于 -1 的值,该值即为分配给插入到 [PERSONNES] 表中新行的一级主键。让我们通过一个示例来看看如何获取该值。
![]() |
![]() |
订单 SQL
可用于获取表中字段 ID 的最新插入值。该查询应在插入操作完成后执行。 这与 SGBD、[Firebird] 和 [Postgres] 不同,后者是在插入之前查询所添加人员的primary key值, 但这与 SGBD 和 MySQL 中的主键生成机制类似。我们将在 [personnes-sqlexpress.xml] 文件中使用它,该文件汇总了基于数据库生成的 SQL 命令。
20.2. [dao] 和 [service] 层的 Eclipse 项目
为了开发基于数据库 [SQL Server Express] 的应用程序中的 [dao] 和 [service] 层,我们将使用以下 Eclipse 项目 [mvc-personnes-06]:

该项目是一个简单的 Java 项目,并非 Tomcat Web 项目。
文件夹 [src]
该文件夹包含 [dao] 和 [service] 层的源代码:

所有文件名中包含 [sqlexpress] 的文件,相对于 Firebird、Postgres 以及 MySQL 版本而言,可能已进行修改,也可能未作修改。下文仅描述其中经过修改的文件。
文件夹 [database]
该文件夹包含用于创建 SQL Express 人员数据库的脚本:
![]()
文件夹 [lib]
该文件夹包含应用程序所需的存档文件:
![]() |
值得注意的是,其中包含 [sqljdbc.jar]、SGBD 和 [Sql Server Express] 的 JDBC 驱动程序。所有这些存档文件均属于 Eclipse 项目的 Classpath。
20.3. [dao] 层
[dao] 层如下:

本文仅介绍与版本 [Firebird] 相比的变化。
映射文件 [personne-sqlexpress.xml] 如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap>
<!-- 别名类 [Personne] -->
<typeAlias alias="Personne.classe"
type="istia.st.mvc.personnes.entites.Personne"/>
<!-- 映射表 [PERSONNES] - 对象 [Personne] -->
<resultMap id="Personne.map"
class="istia.st.mvc.personnes.entites.Personne">
<result property="id" column="ID" />
<result property="version" column="VERSION" />
<result property="nom" column="NOM"/>
<result property="prenom" column="PRENOM"/>
<result property="dateNaissance" column="DATENAISSANCE"/>
<result property="marie" column="MARIE"/>
<result property="nbEnfants" column="NBENFANTS"/>
</resultMap>
<!-- 所有人员的列表 -->
<select id="Personne.getAll" resultMap="Personne.map" > select ID, VERSION, NOM,
PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES</select>
<!-- 获取特定人员 -->
<select id="Personne.getOne" resultMap="Personne.map" >select ID, VERSION, NOM,
PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES WHERE ID=#值#</select>
<!-- 添加人员 -->
<insert id="Personne.insertOne" parameterClass="Personne.classe">
insert into
PERSONNES(VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS)
VALUES(#版本#, #姓#, #名#, #dateNaissance#, #已婚#,
#nbEnfants#)
<selectKey keyProperty="id">
select @@IDENTITY as value
</selectKey>
</insert>
<!-- 更新人员信息 -->
<update id="Personne.updateOne" parameterClass="Personne.classe"> update
PERSONNES set VERSION=#版本#+1, NOM=#姓#, PRENOM=#名#, DATENAISSANCE=#dateNaissance#,
MARIE=#玛丽#, NBENFANTS=#nbEnfants# WHERE ID=#id# 以及
VERSION=#版本#</update>
<!-- 删除人员 -->
<delete id="Personne.deleteOne" parameterClass="int"> delete FROM PERSONNES WHERE
ID=#值# </delete>
<!-- 获取最后插入人员的主键值 [id] -->
<select id="Personne.getNextId" resultClass="int">select
LAST_INSERT_ID()</select>
</sqlMap>
其内容与 [personnes-firebird.xml] 相同,仅存在以下细微差异:
- SQL 中的“Personne.insertOne”指令在第29-37行发生了变更:
- 插入指令 SQL 在 SELECT 之前执行,后者将用于获取插入行主键的值
- 插入语句 SQL 未为表 [PERSONNES] 的列 ID 提供值
这反映了我们在第 20.1 节中讨论过的插入示例。需要注意的是,这里出现了第 19.3 节中针对 MySQL 描述的不同线程同时插入的问题。
[dao] 层的实现类 [DaoImplCommon] 与前三个版本相同。
[dao]层的配置已调整为SGBD和[SQL Express]。因此,配置文件[spring-config-test-dao-sqlexpress.xml]如下:
<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 数据源 DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value>
</property>
<property name="url">
<value>jdbc:sqlserver://localhost\\SQLEXPRESS:4000;databaseName=dbpersonnes</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value>msde</value>
</property>
</bean>
<!-- SqlMapCllient -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="configLocation">
<value>classpath:sql-map-config-sqlexpress.xml</value>
</property>
</bean>
<!-- 访问 [dao] 层的权限 -->
<bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
</bean>
</beans>
- 第 5-19 行: Bean [dataSource] 现指向数据库 [SQL Express] [dbpersonnes],其管理员为 [sa],密码为 [msde]。 读者应根据自身环境修改此配置。
- 第 31 行:类 [DaoImplCommon] 是 [dao] 层的实现类
第 11 行需要说明:
- //localhost:表示 SQL Express 服务器与我们的 Java 应用程序位于同一台机器上
- \\SQLEXPRESS:是 SQL Server 的一个实例名称。似乎可以同时运行多个实例。 因此,为所连接的实例命名是合理的。该名称可通过通常与 SQL Express 同时安装的 [SQL Server Configuration Manager] 获取:


- 4000:SQL Express的监听端口。该端口取决于服务器的配置。默认情况下,它使用动态端口,因此无法提前确定。 因此,在 JDBC 的 URL 中未指定端口。在此示例中,我们使用的是固定端口 4000。该端口通过以下配置设置:
![]() |
- 属性 dataBaseName 用于指定要使用的数据库。该数据库是使用客户端 EMS 创建的:

完成这些修改后,即可进行测试。
20.4. 对图层 [dao] 和 [service] 的测试
[dao] 和 [service] 这两款尿布的测试结果与 [Firebird] 版本相同。测试结果如下:
![]() |
测试结果表明,[DaoImplCommon] 实现版本已成功通过测试。与 SGBD 和 [Firebird] 版本不同,我们无需对该类进行派生。
20.5. [web] 应用程序测试
为了测试基于 SGBD 和 [SQL Server Express] 的 Web 应用程序,我们将按照构建先前 Web 项目的方法,构建一个 Eclipse 项目 [mvc-personnes-06B]。
我们将 [mvc-personnes-05B] Web 项目部署到 Tomcat 中:
![]() | ![]() |
Express 服务器 SGBD SQL 已启动。此时表 [PERSONNES] 的内容如下:

随后启动 Tomcat。通过浏览器访问 URL [http://localhost:8080/mvc-personnes-06B]:

我们通过 通过链接 [Ajout] 添加一位新用户:
![]() | ![]() |
我们在数据库中验证新增记录:

请读者进行其他测试:[modification, suppression]。








