🐟 数据库系统原理课程设计,Drug Inventory Management System,基于 SSM 框架的医院药品库存管理系统。
🐟 数据库系统原理课程设计,Drug Inventory Management System,基于 SSM 框架的医院药品库存管理系统。
数据库应用系统:使用数据库的各类信息系统。
广义的数据库设计:数据库及其应用系统的设计,即整个数据库应用系统。
狭义的数据库设计:设计数据库本身,即设计数据库的各级模式并建立数据库。
设计一个好的数据库与设计一个好的数据库应用系统是密不可分的,一个好的数据库结构是应用系统的基础,特别在实际的系统开发项目中两者更是密切相关、并行进行的。
数据库设计 (database design) 的一般定义:数据库设计是指对于一个给定的应用环境,构造 (设计) 优化的数据库逻辑模式和物理结构,并据此建立数据库及其应用系统,使之能够有效地存储和管理数据,满足各种用户的应用需求,包括信息管理要求和数据操作要求。
信息管理要求是指在数据库中应该存储和管理哪些数据对象;数据操作要求是指对数据对象需要进行哪些操作,如查询、增、删、改、统计等操作。
数据库设计的目标:为用户和各种应用系统提供一个信息基础设施和高效的运行环境。
高效的运行环境指数据库数据的存取效率、数据库存储空间的利用率、数据库系统运行管理的效率等都是最高的。
在数据库设计过程中,需求分析和概念结构设计可以独立于任何数据库管理系统进行,逻辑结构设计和物理结构设计与选用的数据库管理系统密切相关。
根据结构化系统设计的方法,考虑数据库及其应用系统开发全过程,将数据库设计分为以下 6 个阶段:
设计一个完善的数据库应用系统是不可能一蹴而就的,它往往是上述 6 个阶段的不断反复。
数据库设计过程中的各个阶段关于数据特性的设计描述:
设计阶段 | 设计描述 |
---|---|
需求分析 | 数字字典、全系统中数据项、数据结构、数据流、数据存储的描述 |
概念结构设计 | 概念模型 (E-R 图)、数据字典 |
逻辑结构设计 | 某种数据模型 (关系 / 非关系) |
物理结构设计 | 存储安排、存取方法选择、存取路径建立 |
数据库实施 | 创建数据库模式、装入数据、数据库试运行 |
数据库运行和维护 | 性能监测、转储 / 恢复、数据库重组和重构 |
数据库设计过程中的各级模式:
在需求分析阶段综合各个用户的应用需求;在概念结构设计阶段形成独立于机器特点、独立于各个关系数据库管理系统产品的概念模式 (E-R 图);在逻辑结构设计阶段将 E-R 图转换成具体的数据库产品支持的数据模型,如关系模型,形成数据库逻辑模式,然后根据用户处理的要求、安全性的考虑,在基本表的基础上再建立必要的视图,形成数据的外模式;在物理结构设计阶段,根据关系数据库管理系统的特点和处理的需要进行物理存储安排,建立索引,形成数据库内模式。
需求分析必须准确了解与分析用户需求 (包括数据与处理)。
设计描述:数字字典、全系统中数据项、数据结构、数据流、数据存储的描述。
任务:通过详细调查现实世界要处理的对象 (组织、部门、企业等),充分了解原系统 (手工系统或计算机系统) 的工作概况,明确用户的各种需求,然后在此基础上确定新系统的功能。新系统必须充分考虑今后可能的扩充和改变,不能仅仅按当前应用需求来设计数据库。调查的重点是 “数据” 和 “处理”,通过调查、收集与分析,获得用户对数据库的如下要求:
参考:
数据字典是进行详细的数据收集和数据分析所获得的主要成果。它是关于数据库中数据的描述,即元数据,而不是数据本身。数据字典是在需求分析阶段建立,在数据库设计过程中不断修改、充实、完善的。它在数据库设计中占有很重要的地位。数据字典通常包括数据项、数据结构、数据流、数据存储和处理过程几部分。其中数据项是数据的最小组成单位,若干个数据项可以组成一个数据结构。数据字典通过对数据项和数据结构的定义来描述数据流、数据存储的逻辑内容。
数据项:数据项是不可再分的数据单位。对数据项的描述通常包括以下内容:
数据项描述 = { 数据项名, 数据项含义说明, 别名, 数据类型, 长度, 取值范围, 取值含义, 与其他数据项的逻辑关系, 数据项之间的联系 }
数据项名 | 数据项含义说明 | 数据类型 | 长度 | 取值范围 | 取值含义 | 与其他数据项的逻辑关系 | 数据项之间的联系 |
---|---|---|---|---|---|---|---|
Ano | 库存管理员编号,唯一标识每个库存管理员 | VARCHAR | 20 | ||||
Aname | 库存管理员姓名 | VARCHAR | 20 | Ano→Aname | |||
Asex | 库存管理员性别 | BIT | 1 | { 0, 1 } | 0 代表女,1 代表男 | Ano→Asex | |
Aage | 库存管理员年龄 | SMALLINT | 2 | [0, 32767] | Ano→Aage | ||
Apwd | 库存管理员登陆密码 | VARCHAR | 20 | Ano→Apwd | |||
Dno | 医生编号,唯一标识每个医生 | VARCHAR | 20 | ||||
Dname | 医生姓名 | VARCHAR | 20 | Dno→Dname | |||
Dsex | 医生性别 | BIT | 1 | { 0, 1 } | 0 代表女,1 代表男 | Dno→Dsex | |
Dage | 医生年龄 | SMALLINT | 2 | [0, 32767] | Dno→Dage | ||
Dpwd | 医生登陆密码 | VARCHAR | 20 | Dno→Dpwd | |||
Nno | 发药处护士编号,唯一标识每个护士 | VARCHAR | 20 | ||||
Nname | 发药处护士姓名 | VARCHAR | 20 | Nno→Nname | |||
Nsex | 发药处护士性别 | BIT | 1 | { 0, 1 } | 0 代表女,1 代表男 | Nno→Nsex | |
Nage | 发药处护士年龄 | SMALLINT | 2 | [0, 32767] | Nno→Nage | ||
Npwd | 发药处护士登陆密码 | VARCHAR | 20 | Nno→Npwd | |||
Sno | 药品供应商编号,唯一标识每个药品供应商 | VARCHAR | 20 | ||||
Sname | 药品供应商名称 | VARCHAR | 20 | Sno→Sname | |||
Saddr | 药品供应商地址 | VARCHAR | 60 | Sno→Saddr | |||
Sphone | 药品供应商电话 | VARCHAR | 20 | Sno→Sphone | |||
PDno | 药品编号,唯一标识每种药品 | VARCHAR | 20 | ||||
PDname | 药品名称 | VARCHAR | 20 | PDno→PDname | |||
PDlife | 药品保质期 | SMALLINT | 2 | [0, 32767] | PDno→PDlife | ||
PDbatch | 药品批次,结合药品编号来唯一标识每批药品 | DATE | |||||
PDnum | 药品数量 | SMALLINT | 2 | [0, 32767] | (PDno, PDbatch)→PDnum | ||
SAno | 药品入库库存管理员编号 | VARCHAR | 20 | SAno ∈ List<Ano > |
(PDno, PDbatch)→SAno | ||
Stime | 药品入库时间 | DATETIME | Stime ≥ PDbatch | (PDno, PDbatch)→Stime | |||
DAno | 药品销毁库存管理员编号 | VARCHAR | 20 | DAno ∈ List<Ano > |
(PDno, PDbatch)→DAno | ||
Dtime | 药品销毁时间 | DATETIME | Dtime ≥ Stime | (PDno, PDbatch)→Dtime | |||
Pno | 处方编号,唯一标识每个处方 | INT | [1, 2147483647] | ||||
Pid | 病人身份证号 | VARCHAR | 20 | Pno→Pid | |||
Ptime | 处方开出时间 | DATETIME | Pno→Ptime | ||||
Htime | 处方处理时间 | DATETIME | Htime ≥ Ptime | Pno→Htime | |||
Pstate | 处方状态 | BIT | 1 | { 0, 1 } | 0 代表未处理,1 代表已处理 | Pno→Pstate |
数据结构:数据结构反映了数据之间的组合关系。一个数据结构可以由若干数据项组成,也可以由若干个数据结构组成,或由若干个数据项和数据结构混合组成。对数据结构的描述通常包括以下内容:
数据结构描述 = { 数据结构名, 含义说明, 组成:{数据项或数据结构} }
数据结构名 | 含义说明 | 组成:{数据项或数据结构} |
---|---|---|
Admin | 库存管理员,定义了一个库存管理员的有关信息 | { Ano, Aname, Asex, Aage, Apwd } |
Doctor | 医生,定义了一个医生的有关信息 | { Dno, Dname, Dsex, Dage, Dpwd } |
Nurse | 发药处护士,定义了一个护士的有关信息 | { Nno, Nname, Nsex, Nage, Npwd } |
Supplier | 药品供应商,定义了一个药品供应商的有关信息 | { Sno, Sname, Saddr, Sphone } |
Drug | 药品,定义了一种药品的有关信息 | { PDno, PDname, PDlife, PDnum } |
InventoryDrug | 库存药品,定义了一批库存药品的有关信息 | { PDno, PDname, PDlife, PDbatch, PDnum, Sno, SAno, Stime } |
DestroyedDrug | 已销毁药品,定义了一批已销毁药品的有关信息 | { PDno, PDname, PDlife, PDbatch, PDnum, Sno, SAno, Stime, DAno, Dtime } |
Prescription | 处方,定义了一个处方的有关信息 | { Pno, Pid, Dno, Ptime, Nno, Htime, Pstate, ListDrug } |
数据流:数据流是数据结构在系统内传输的路径。对数据流的描述通常包括以下内容:
数据流描述 = { 数据流名, 说明, 数据流来源, 数据流去向, 组成:{数据结构}, 平均流量, 高峰期流量 }
数据流名 | 说明 | 数据流来源 | 数据流去向 | 组成:{数据结构} | 平均流量 | 高峰期流量 |
---|
数据存储:数据存储是数据结构停留或保存的地方,也是数据流的来源和去向之一。它可以是手工文档或手工凭单,也可以是计算机文档。对数据存储的描述通常包括以下内容:
数据存储描述 = { 数据存储名, 说明, 编号, 输入的数据流, 输出的数据流, 组成:{数据结构}, 数据量, 存取频度, 存取方式 }
数据存储名 | 说明 | 编号 | 输入的数据流 | 输出的数据流 | 组成:{数据结构} | 数据量 | 存取频度 | 存取方式 |
---|
处理过程:处理过程的具体处理逻辑一般用判定表或判定树来描述。数据字典中只需要描述处理过程的说明性信息即可,通常包括以下内容:
处理过程描述 = { 处理过程名, 说明, 输入:{数据流}, 输出:{数据流}, 处理:{简要说明} }
处理过程名 | 说明 | 输入:{数据流} | 输出:{数据流} | 处理:{简要说明} |
---|
参考:
概念结构设计通过对用户需求进行综合、归纳与抽象,形成一个独立于具体数据库管理系统的概念模型。
设计描述:概念模型 (E-R 图)、数据字典。
任务:概念结构设计的第一步就是对需求分析阶段收集到的数据进行分类、组织,确定实体、实体的属性、实体之间的联系类型,形成 E-R 图。
逻辑结构设计是将概念结构转换为某个数据库管理系统所支持的数据模型,并对其进行优化。
设计描述:某种数据模型 (关系 / 非关系)。
任务:把概念结构设计阶段设计好的基本 E-R 图转换为与选用数据库管理系统产品所支持的数据模型相符合的逻辑结构。将概念模型转换为全局逻辑模型后,还应该根据局部应用需求,结合具体关系数据库管理系统的特点设计用户的外模式。
关系数据模型的优化通常以规范化理论为指导,方法为:
定义数据库全局模式主要是从系统的时间效率、空间效率、易维护等角度出发。
定义用户外模式时可以注重考虑用户的习惯与方便,具体包括以下几方面:
一共设计了 5 个用户子模式 (视图)——DrugView
、InventoryDrugView
、DestroyedDrugView
、AllPDbatchView
、DrugDoctorView
,这 5 个视图都是为了简化数据库用户 (主要是应用程序员) 对系统的使用。
其中 InventoryDrugView
和 DestroyedDrugView
是对先前做了优化分解的两个关系模式的重新连接;DrugView
是对各药品的所有批次进行汇总统计,主要是为了计算各药品的库存总量;AllPDbatchView
是对所有药品批次 (包括现存的批次和已销毁的批次) 的合并汇总查询。
其中比较复杂的是 DrugDoctorView
,对于应用系统的三类人员来说,库存管理员和发药处护士的视图所看到的药品库存量是一样的,都是真实的药品库存量,只有医生的视图不一样,医生所看到的药品库存量应该是真实的药品库存量减去已开出但未处理的处方当中所包含的药品库存量。
物理结构设计是为逻辑数据模型选取一个最适合应用环境的物理结构 (包括存储结构和存取方法)。
设计描述:存储安排、存取方法选择、存取路径建立。
内容:主要包括为关系模式选择存取方法,以及设计关系、索引等数据库文件的物理存储结构。
数据库系统是多用户共享的系统,对同一个关系要建立多条存取路径才能满足多用户的多种应用要求。物理结构设计的任务之一是根据关系数据库管理系统支持的存取方法确定选择哪些存取方法。
存取方法是快速存取数据库中数据的技术。所谓选择索引存取方法,实际上就是根据应用要求确定对关系的哪些属性列建立索引、哪些属性列建立组合索引、哪些索引要设计为唯一索引等。
关系上定义的索引数并不是越多越好,系统为维护索引要付出代价,查找索引也要付出代价。例如,若一个关系的更新频率很高,这个关系上定义的索引数不能太多。因为更新一个关系时,必须对这个关系上有关的索引做相应的修改。
数据库管理系统一般提供多种存取方法。常用的存取方法为 索引方法 和 聚簇 (clustering) 方法。B+ 树索引和 hash 索引是数据库中经典的存取方法,使用最普遍。
B+ 树索引存取方法的选择 (也是一般索引存取方法的选择):
hash 索引存取方法的选择:如果一个关系的属性主要出现在等值连接条件中或主要出现在等值比较选择条件中,而且满足下列两个条件之一,则此关系可以选择 hash 索引存取方法。
聚簇存取方法的选择:
为了提高某个属性 (或属性组) 的查询速度,把这个或这些属性上具有相同值的元组集中存放在连续的物理块中称为聚簇。该属性 (或属性组) 称为 聚簇码 (cluster key)。聚簇功能可以大大提高按聚簇码进行查询的效率。
聚簇功能不但适用于单个关系,也适用于经常进行连接操作的多个关系。即把多个连接关系的元组按连接属性值聚集存放。这就相当于把多个关系按“预连接”的形式存放,从而大大提高连接操作的效率。
一个数据库可以建立多个聚簇,一个关系只能加入一个聚簇。选择聚簇存取方法,即确定需要建立多少个聚簇,每个聚簇中包括哪些关系。
首先设计候选聚簇,一般来说:
然后检查候选聚簇中的关系,取消其中不必要的关系。
综合考量之后,我们认为不建立索引和聚簇的话运行各种事务的总代价反而最小,所以我们不建立索引和聚簇。
在数据库实施阶段,设计人员运用数据库管理系统提供的数据库语言及其宿主语言,根据逻辑设计和物理设计的结果建立数据库,编写与调试应用程序,组织数据入库,并进行试运行。
设计描述:创建数据库模式、装入数据、数据库试运行。
USE master;
IF EXISTS (SELECT *
FROM sysdatabases
WHERE name = 'DIMS')
BEGIN
DROP DATABASE DIMS;
END;
CREATE DATABASE DIMS;
IF NOT EXISTS (SELECT *
FROM syslogins
WHERE name = 'dba')
BEGIN
CREATE LOGIN dba WITH PASSWORD = 'abcd1234@', DEFAULT_DATABASE = DIMS;
END
GO
USE DIMS;
CREATE USER dba FOR LOGIN dba WITH DEFAULT_SCHEMA = dbo;
EXEC sp_addrolemember 'db_owner', 'dba';
CREATE TABLE Admin( -- 库存管理员
Ano VARCHAR(20) PRIMARY KEY, -- 编号
Aname VARCHAR(20) NOT NULL, -- 姓名
Asex BIT NOT NULL DEFAULT 1, -- 性别 (1 为男,0 为女)
Aage SMALLINT CHECK (Aage >= 0) NOT NULL, -- 年龄
Apwd VARCHAR(20) NOT NULL DEFAULT '00000000' -- 登陆密码
);
CREATE TABLE Doctor( -- 医生
Dno VARCHAR(20) PRIMARY KEY, -- 编号
Dname VARCHAR(20) NOT NULL, -- 姓名
Dsex BIT NOT NULL DEFAULT 1, -- 性别 (1 为男,0 为女)
Dage SMALLINT CHECK (Dage >= 0) NOT NULL, -- 年龄
Dpwd VARCHAR(20) NOT NULL DEFAULT '00000000' -- 登陆密码
);
CREATE TABLE Nurse( -- 发药处护士
Nno VARCHAR(20) PRIMARY KEY, -- 编号
Nname VARCHAR(20) NOT NULL, -- 姓名
Nsex BIT NOT NULL DEFAULT 1, -- 性别 (1 为男,0 为女)
Nage SMALLINT CHECK (Nage >= 0) NOT NULL, -- 年龄
Npwd VARCHAR(20) NOT NULL DEFAULT '00000000' -- 登陆密码
);
CREATE TABLE Supplier( -- 供应商
Sno VARCHAR(20) PRIMARY KEY, -- 编号
Sname VARCHAR(60) NOT NULL, -- 名称
Saddr VARCHAR(60) NOT NULL, -- 地址
Sphone VARCHAR(20) NOT NULL -- 电话
);
CREATE TABLE Drug( -- 药品
PDno VARCHAR(20) PRIMARY KEY, -- 编号
PDname VARCHAR(20) NOT NULL, -- 名称
PDlife SMALLINT CHECK (PDlife >= 0) NOT NULL -- 保质期 (天数)
);
CREATE TABLE InventoryDrug( -- 库存药品
PDno VARCHAR(20), -- 编号
PDbatch DATE, -- 批次
PDnum SMALLINT CHECK (PDnum >= 0) NOT NULL, -- 数量
Sno VARCHAR(20) NOT NULL, -- 供应商编号
SAno VARCHAR(20) NOT NULL, -- 入库库存管理员编号
Stime DATETIME NOT NULL DEFAULT GETDATE(), -- 入库时间
PRIMARY KEY(PDno, PDbatch),
FOREIGN KEY (PDno) REFERENCES Drug(PDno),
FOREIGN KEY (Sno) REFERENCES Supplier(Sno),
FOREIGN KEY (SAno) REFERENCES Admin(Ano),
CHECK (DATEDIFF(DAY, PDbatch, Stime) >= 0)
);
CREATE TABLE DestroyedDrug( -- 已销毁药品
PDno VARCHAR(20), -- 编号
PDbatch DATE, -- 批次
PDnum SMALLINT CHECK (PDnum >= 0) NOT NULL, -- 数量
Sno VARCHAR(20) NOT NULL, -- 供应商编号
SAno VARCHAR(20) NOT NULL, -- 入库库存管理员编号
Stime DATETIME NOT NULL, -- 入库时间
DAno VARCHAR(20) NOT NULL, -- 销毁库存管理员编号
Dtime DATETIME NOT NULL DEFAULT GETDATE(), -- 销毁时间
PRIMARY KEY(PDno, PDbatch),
FOREIGN KEY (PDno) REFERENCES Drug(PDno),
FOREIGN KEY (Sno) REFERENCES Supplier(Sno),
FOREIGN KEY (SAno) REFERENCES Admin(Ano),
FOREIGN KEy (DAno) REFERENCES Admin(Ano),
CHECK (DATEDIFF(DAY, PDbatch, Stime) >= 0 AND DATEDIFF(DAY, Stime, Dtime) >= 0)
);
CREATE TABLE Prescription( -- 处方
Pno INT PRIMARY KEY IDENTITY (1, 1), -- 编号
Pid VARCHAR(20) NOT NULL, -- 病人身份证号码
Dno VARCHAR(20) NOT NULL, -- 开出医生编号
Ptime DATETIME NOT NULL, -- 开出时间
Nno VARCHAR(20), -- 处理护士编号
Htime DATETIME, -- 处理时间
Pstate BIT NOT NULL DEFAULT 0, -- 状态 (1 为已处理,0 为未处理)
FOREIGN KEY (Dno) REFERENCES Doctor(Dno),
FOREIGN KEY (Nno) REFERENCES Nurse(Nno),
CHECK (DATEDIFF(DAY, Ptime, Htime) >= 0)
);
CREATE TABLE PID( -- 处方包含的药品
Pno INT, -- 处方编号
PDno VARCHAR(20), -- 药品编号
PDnum SMALLINT CHECK (PDnum >= 0) NOT NULL, -- 药品数量
PRIMARY KEY (Pno, PDno),
FOREIGN KEY (Pno) REFERENCES Prescription(Pno) ON DELETE CASCADE,
FOREIGN KEY (PDno) REFERENCES Drug(PDno)
);
CREATE VIEW DrugView
AS
SELECT d.PDno, d.PDname, d.PDlife, COALESCE(SUM(i.PDnum), 0) AS PDnum
FROM Drug d LEFT OUTER JOIN InventoryDrug i ON d.PDno = i.PDno
GROUP BY d.PDno, d.PDname, d.PDlife;
CREATE VIEW InventoryDrugView
AS
SELECT d.PDno, d.PDname, d.PDlife, i.PDbatch, i.PDnum, i.Sno, i.SAno, i.Stime,
(d.PDlife - DATEDIFF(DAY, i.PDbatch, GETDATE())) AS Rdays
FROM Drug d, InventoryDrug i
WHERE d.PDno = i.PDno;
CREATE VIEW DestroyedDrugView
AS
SELECT d.PDno, d.PDname, d.PDlife, dd.PDbatch, dd.PDnum, dd.Sno, dd.SAno, dd.Stime, dd.DAno, dd.Dtime
FROM Drug d, DestroyedDrug dd
WHERE d.PDno = dd.PDno;
CREATE VIEW AllPDbatchView
AS
SELECT PDno, PDname, PDlife, PDbatch, PDnum, Sno, SAno, Stime, null AS DAno, null AS Dtime, Rdays
FROM InventoryDrugView
UNION
SELECT PDno, PDname, PDlife, PDbatch, PDnum, Sno, SAno, Stime, DAno, Dtime, null AS Rdays
FROM DestroyedDrugView;
CREATE VIEW DrugDoctorView
AS
SELECT d.PDno, d.PDname, d.PDlife, (d.PDnum - (SELECT COALESCE(SUM(PID.PDnum), 0)
FROM Prescription p, PID
WHERE p.Pno = PID.Pno AND p.Pstate = 0
AND PID.PDno = d.PDno)) AS PDnum
FROM DrugView d;
CREATE PROCEDURE DestroyInventoryDrug @PDno VARCHAR(20), @PDbatch DATE,
@DAno VARCHAR(20), @Dtime DATETIME, @returnValue SMALLINT OUTPUT
AS
SET XACT_ABORT ON
BEGIN TRAN
DECLARE @PDnum SMALLINT;
DECLARE @Sno VARCHAR(20);
DECLARE @SAno VARCHAR(20);
DECLARE @Stime DATETIME;
SET @returnValue = 0;
SELECT @PDnum = PDnum, @Sno = Sno, @SAno = SAno, @Stime = Stime
FROM InventoryDrug
WHERE PDno = @PDno AND PDbatch = @PDbatch;
SET @returnValue = @returnValue + @@error;
INSERT INTO DestroyedDrug(PDno, PDbatch, PDnum, Sno, SAno, Stime, DAno, Dtime)
VALUES(@PDno, @PDbatch, @PDnum, @Sno, @SAno, @Stime, @DAno, @Dtime);
SET @returnValue = @returnValue + @@error;
DELETE FROM InventoryDrug
WHERE PDno = @PDno AND PDbatch = @PDbatch;
SET @returnValue = @returnValue + @@error;
COMMIT TRAN
CREATE PROCEDURE HandleRx @Pno INT, @Nno VARCHAR(20), @Htime DATETIME, @returnValue SMALLINT OUTPUT
AS
SET XACT_ABORT ON
BEGIN TRAN
DECLARE @RxDrugPDno VARCHAR(20);
DECLARE @RxDrugPDnum SMALLINT;
DECLARE @BatchPDbatch DATE;
DECLARE @BatchPDnum SMALLINT;
SET @returnValue = 0;
DECLARE RxDrugs CURSOR FOR SELECT PDno, PDnum
FROM PID
WHERE Pno = @Pno;
OPEN RxDrugs;
FETCH NEXT FROM RxDrugs INTO @RxDrugPDno, @RxDrugPDnum;
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE Batches CURSOR FOR SELECT PDbatch, PDnum
FROM InventoryDrug
WHERE PDno = @RxDrugPDno
ORDER BY PDbatch ASC;
OPEN Batches;
FETCH NEXT FROM Batches INTO @BatchPDbatch, @BatchPDnum;
WHILE @@FETCH_STATUS = 0 AND @RxDrugPDnum > 0
BEGIN
IF @BatchPDnum >= @RxDrugPDnum
BEGIN
UPDATE InventoryDrug
SET PDnum = (PDnum - @RxDrugPDnum)
WHERE PDno = @RxDrugPDno AND PDbatch = @BatchPDbatch;
SET @returnValue = @returnValue + @@error;
SET @RxDrugPDnum = 0;
END
ELSE
BEGIN
SET @RxDrugPDnum = @RxDrugPDnum - @BatchPDnum;
UPDATE InventoryDrug
SET PDnum = 0
WHERE PDno = @RxDrugPDno AND PDbatch = @BatchPDbatch;
SET @returnValue = @returnValue + @@error;
END
FETCH NEXT FROM Batches INTO @BatchPDbatch, @BatchPDnum;
END
CLOSE Batches
DEALLOCATE Batches
FETCH NEXT FROM RxDrugs INTO @RxDrugPDno, @RxDrugPDnum;
END
CLOSE RxDrugs
DEALLOCATE RxDrugs
SET @returnValue = @returnValue + @@error;
UPDATE Prescription
SET Nno = @Nno, Htime = @Htime, Pstate = 1
WHERE Pno = @Pno;
SET @returnValue = @returnValue + @@error;
COMMIT TRAN
数据库应用系统经过试运行后即可投入正式运行。
在数据库系统运行过程中必须不断地对其进行评估、调整与修改。
设计描述:性能监测、转储 / 恢复、数据库重组和重构。
参考:
参考:
参考:
下载 JDK 安装包:
配置环境变量:
变量 | 值 |
---|---|
JAVA_HOME | C:\Program Files\Java\jdk1.8.0_231 |
JRE_HOME | C:\Program Files\Java\jre1.8.0_231 |
Path | ;%JAVA_HOME%\bin |
从官网下载相应的 Tomcat Binary Distributions 安装包文件 32-bit/64-bit Windows Service Installer
。
双击运行下载的安装文件,按照提示一步一步安装并配置。
配置环境变量:
变量 | 值 |
---|---|
TOMCAT_HOME | C:\Program Files\Apache Software Foundation\Tomcat 9.0 |
CATALINA_HOME | C:\Program Files\Apache Software Foundation\Tomcat 9.0 |
Path | ;%TOMCAT_HOME%\bin;%CATALINA_HOME%\lib |
参考:
新建一个名为 DIMS
的 Dynamic Web Project
,Target runtime
选择上一步在 Eclipse 当中配置的 Apache Tomcat v9.0
,Dynamic web module version
选择最新版本,Configuration
选择 Default Configuration for Apache Tomcat v9.0
,其它选项不作更改,点击 Next
。
将 Default output folder
的值改为 WebContent\WEB-INF\classes
,点击 Next
。
勾选 Generate web.xml deployment descriptor
,点击 Finish
。
测试项目是否可以发布成功,参考:
后续需要导入的 jar 包都复制到项目的 WebContent\WEB-INF\lib
目录当中来。
下载 spring-5.2.1.RELEASE-dist.zip
并解压。
将 spring-5.2.1.RELEASE-dist.zip
解压路径的 libs
目录下的一部分 jar 包复制到项目的 WebContent\WEB-INF\lib
目录当中来,需要的 jar 包如下:
将 spring-5.2.1.RELEASE-dist.zip
解压路径的 libs
目录下的一部分 jar 包复制到项目的 WebContent\WEB-INF\lib
目录当中来,需要的 jar 包如下:
需要导入的 jar 包:
参考:
参考:
在项目的 Java Resources
项中新建一个名为 resource
的 'source folder',然后在其下新建两个 XML 文件。
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
applicationContext-mvc.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- mvc 静态资源放行 —— 允许访问图片等静态资源 -->
<mvc:default-servlet-handler/>
<!-- mvc 支持注解 Controller -->
<context:annotation-config/>
<mvc:annotation-driven/>
<!-- 设置扫描包的路径 Controller -->
<context:component-scan base-package="com.dims.web.controller"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀和后缀 -->
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
在项目的 WebContent\WEB-INF\
目录下找到 web.xml 文件,进行配置:
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" version="4.0">
<display-name>DIMS</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 解决乱码问题 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 加载 spring 配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 启动的时候加载 spring 的配置文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 启动的时候加载 springmvc 的配置文件 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
需要导入的 jar 包:
除此之外还需要导入 SQL Server 的 JDBC Driver jar 包:
在 resource
目录下,新建一个名为 jdbc.properties
的文件:
jdbc.properties:
jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://localhost:1433;databaseName=DIMS
jdbc.username=dba
jdbc.password=abcd1234@
在 Spring 的配置文件当中,配置 MyBatis:
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- jdbc.properties → dataSource → sqlSessionFactory → mapper → service → action -->
<!-- jdbc.properties 加载 JDBC 配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- dataSource 配置数据源 (连接池) -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<!-- 依赖注入连接池需要的属性 -->
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引入数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载所有的 mapper 路径 -->
<property name="mapperLocations" value="classpath:com/dims/mapper/*Mapper.xml" />
<!-- 配置别名 -->
<property name="typeAliasesPackage" value="com.dims.domain" />
</bean>
<!-- 扫描 mapper 层 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描 mapper 接口的包路径 -->
<property name="basePackage" value="com.dims.mapper" />
</bean>
<!-- 扫描 service 层 -->
<context:component-scan base-package="com.dims.service" />
<!-- action -->
</beans>
在 resource
目录下,新建一个名为 log4j.properties
的文件:
log4j.properties:
log4j.rootLogger=ERROR, stdout
log4j.logger.com.sms=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
从 ACE 的 GitHub 项目页面下载该项目的压缩包,解压后将解压路径下的 assets
文件夹复制到项目的 WebContent
目录下。
需要导入的 jar 包:
界面测试:反复不间断地点击各窗体连接,测试其连接情况是否达到预期效果。
发现的问题:
360 安全浏览器使用兼容模式时,部分链接无法正确处理。(极速模式可行)
客户端页面报错:
HTTP Status 400 - 错误的请求
Type:异常报告
消息:Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
描述:由于被认为是客户端对错误 (例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。
Exception:
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:468)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:292)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
服务器端 Tomcat 报错:
十二月 22, 2019 3:28:49 下午 org.apache.coyote.http11.Http11Processor service
信息: 解析 HTTP 请求 header 错误
Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:468)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:292)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
解决方法:尚未解决。
功能测试:对系统各功能模块逐一测试,尽最大可能地发现潜在 BUG 错误。
发现的问题:
没有对处方表单当中的病人身份证号码输入栏作输入限制,该输入栏可以输入中文字符和特殊符号。
解决方法:在病人身份证号码的输入标签当中限制文本输入类型 (没有完全解决,仍然可以输入下划线 _
):
<input ... onKeyUp="value=value.replace(/[\W]/g,'')" />
在新增药品入库表单当中,药品数量输入栏的最小值输入限制设置为 0,而数量为 0 的药品批次没有意义。
解决方法:对于新增药品入库表单,限制药品数量输入标签的输入最小值为 1;对于修改药品入库表单,限制药品数量输入标签的输入最小值为 0。
$('#spinner1').ace_spinner({value:${type ? '1' : '0'}, min:${type ? '1' : '0'}, max:10000, step:100, btn_up_class:'btn-info', btn_down_class:'btn-info'})
.closest('.ace-spinner')
.on('changed.fu.spinbox', function(){
//console.log($('#spinner1').val())
});
性能测试:将程序以局域网的形式连接数据库,查看数据连接是否满足多用户的要求。
需求测试:根据需求分析的内容,给使用者进行试用,测试软件是否和当初设计的一样能满足各用户需求。
发现的问题:
医生和发药处护士的若干需要查询处方列表的页面没有对查询结果进行初始化的排序。
解决方法:
原查询代码:
SELECT *
FROM Prescription
WHERE Dno = #{Dno};
修改后的查询代码:
SELECT *
FROM Prescription
WHERE Dno = #{Dno}
ORDER BY Ptime DESC;
javax.el.PropertyNotFoundException: 类型[com.dims.domain.InventoryDrug]上找不到属性[Sno]
:
参考:
关于 jsp 页面当中 Date / DateTime 类型的值的显示格式问题:
参考:
关于 jsp 页面当中实型值的显示格式问题:
参考:
关于 Model Attribute
和 Session Attribute
的作用域问题:
参考:
SpringMVC 当中 Controller 层能不能有重载方法?
参考:
怎么把聚合函数 SUM
的 NULL
聚合结果值改为 0
?
参考:
MyBatis Mapper 层的 XML 映射文件报错 The content of elements must consist of well-formed character data or markup.
:
参考:
怎么把 SQL Server GETDATE()
函数返回的 DATETIME
类型的值转换为 DATE
类型的值?
参考:
在 SQL Server 当中怎么计算时间差?
参考:
怎样进行内网穿透,让外网能访问本地的应用?
参考:
Java 如何对枚举类型的变量进行赋值?
参考:
Java 如何对 Date 类型的变量进行赋值?
参考:
URL 中参数带空格应该如何表示?
参考:
关于 Java 的重写 (Override) 与重载 (Overload):
参考:
MyBatis 的 Mapper 层接口方法可以重载吗?
参考:
有空再看:
MyBatis 如何调用存储过程?
参考:
SQL Server 事务的使用是为了确保数据的一致性,但是当操作 (增删改) 发生由 NULL 值引发的错误时,事务会跳过错误继续执行正常的语句,如何让该种事务回滚?
参考:
MyBatis insert Mapper 如何获取自增主键值?
参考:
SQL Server 怎么查询所有登录用户?
参考:
HTML 表单隐藏域怎么实现?
参考:
SQL Server 游标的使用?
参考:
SQL Server 定义游标时的子查询不能使用 ORDER BY 语句?
参考:
HTML 如何限制 input 输入栏的文本输入?
参考: