1.需求分析
1.1系统分析
1.1.1系统开发背景与开发目的
现如今,随着国内经济的快速发展,汽车租赁行业也如同繁星-般呈现欣欣向荣之势,面对越来越庞大的市场,传统的管理方法即人工管理已经无法适应日渐繁多的业务性息,因此,人们必须开发出全新的管理方法,以期达到提高管理效率的目的。
在我国,租赁业发展迅速,将高科技融入租赁业,定能促进行业的平稳发展,也能保证行业发展的高效性和可持续性。
针对传统的汽车租赁管理系统中存在的问题以及一些可以继续完善的地方,利用计算机网络以及数据库等高科技手段,建立起一套集人员管理,车辆的各项性能管理于一体的租赁管理系统,实现管理的计算机辅助,也使得管理便捷化,高效化。此系统既能单独使用,又能配合现有的其他汽车租赁管理系统使用,来补全其功能。同时,该系统能够配合前台网站,实现客户在线看、选、租车,租赁方根据客户要求为客户提供服务的一体化进程。
1.1.2数据需求与处理
汽车租赁的整个业务流程中,主要的参与者是客户和业务员
- 客户
- 需要查看出租车辆信息,了解租赁汽车的价格
- 业务员
- 主要负责合同的签订,登记租赁信息,确定服务费用
1.1.3数据存储
数据存储主要有
- 客户信息
- 汽车信息
- 租赁价格信息
- 租赁登记信息
- 租赁费用
1.2数据信息
1.2.1静态数据信息
- 客户信息(CLIENT)
属性名 | 存储代码 |
---|---|
客户编号 | ClNo |
客户名字 | ClName |
客户性别 | ClGender |
客户身份证号 | ClId |
联系电话 | ClTel |
客户住址 | ClAddress |
- 汽车信息(CAR)
属性名 | 存储代码 |
---|---|
车辆编号 | CaId |
车牌号 | CaPlate |
车辆型号 | CaModel |
颜色 | CaColor |
租赁状态 | CaState |
- 租赁登记信息(RENT_REG)
属性名 | 存储代码 |
---|---|
租赁单号 | RId |
客户编号 | ClId |
车辆编号 | CaId |
租赁开始时间 | StartTime |
归还日期 | ReturnTime |
- 租赁费用信息(RENT_FEE)
属性名 | 存储代码 |
---|---|
租赁单号 | RId |
租期内费用 | FLease |
超期费用 | FOverdue |
车辆损坏费用 | FDamage |
总费用 | FTotal |
- 租赁价格信息(RENT_PRICE)
属性名 | 存储代码 |
---|---|
车辆编号 | CaId |
价格 | Price |
1.3角色和用户需求
主要角色有客户、业务员、经理和系统管理员,每个角色的主要任务如下
- 客户:看车租车,创建个人信息
- 业务员:登记租赁情况、计算费用、收费、记录车辆信息
- 经理:拥有业务员的所有权限,同时制定收费策略
- 系统管理员:管理数据库内所有数据
权限需求如下:
角色 | 权限 |
---|---|
客户 | 1.可查看汽车信息、个人信息、个人租赁信息; 2.可修改个人信息 |
业务员 | 1.可查看汽车信息、客户信息、租赁信息; 2.可创建租赁信息、汽车信息; 3.可修改租赁信息、汽车信息 |
经理 | 1.可查看汽车信息、客户信息、租赁信息; 2.可创建租赁信息、汽车信息; 3.可修改租赁信息,租赁价格信息,汽车信息 |
系统管理员 | 可查看、创建、修改、删除所有信息 |
2.概念设计
2.1确定实体及属性
- 客户{客户编号,客户名字,客户性别,客户身份证号,联系电话,客户住址}
- 租赁登记{租赁单号,客户编号,车辆编号,租赁开始时间,归还日期}
- 汽车{车辆编号,车牌号,车辆型号,颜色,租赁状态}
- 租赁费用{租赁单号,租期内费用,超期费用,车辆损坏费用,总费用}
- 租赁价格{车辆编号,价格}
2.2关系说明
- 客户与租赁登记表:一对多关系,一个客户可以没有租赁,也可以是多个;一个租赁登记必然对应一个用户.且租赁登记非标识符依赖客户.
- 租赁登记与汽车:一对一关系,一辆汽车可以没有,也可以至多有一个租赁登记(同一时间段有效,不考虑多次租赁);一个租赁登记对应且仅对应一辆车.租赁登记非标识符依赖汽车
- 租赁登记与租赁费用:一对一关系,一个租赁登记必然有一个租赁费用;以合租赁费用也必然有一个租赁登记.租赁费用标识符依赖租赁登记
- 汽车与租赁价格:一对一关系,一辆汽车必然有一个租赁价格;一个租赁价格必然对应一辆车(这里采用的一辆车一种价格的方式,因为型号、新旧程度都会影响租赁价格).租赁价格标识符依赖汽车.
2.2概念数据模型
由PowerDesigner设计的概念数据模型如下:
3.逻辑设计
3.1逻辑数据模型
逻辑模型的实体与概念模型一样,也不存在多对多关系,所以在概念模型的基础上生成逻辑模型.
具体步骤:选取菜单栏工具–>生成逻辑数据模型–>确定生成
得到如下逻辑数据模型
4.物理模型
4.1物理数据模型
在概念模型的基础上生成逻辑模型.
具体步骤:选取菜单栏工具–>生成物理数据模型–>确定生成
5.物理模型转换为SQL语言
具体步骤:选取菜单栏工具选项–>选取生成数据库选项–>重命名文件–>生成
得到如下代码(使用时需去掉前面的删除操作)
drop index CAR_PK;
drop table CAR;
drop index CLIENT_PK;
drop table CLIENT;
drop index RENT_FEE_PK;
drop table RENT_FEE;
drop index RENT_PRICE_PK;
drop table RENT_PRICE;
drop index Rent_FK;
drop index registration_FK;
drop index RENT_REG_PK;
drop table RENT_REG;
/*==============================================================*/
/* Table: CAR */
/*==============================================================*/
create table CAR (
CaId SERIAL not null,
CaPlate CHAR(8) not null,
CaModel VARCHAR(20) not null,
CaColor VARCHAR(6) not null,
CaState BOOL not null,
constraint PK_CAR primary key (CaId)
);
/*==============================================================*/
/* Index: CAR_PK */
/*==============================================================*/
create unique index CAR_PK on CAR (
CaId
);
/*==============================================================*/
/* Table: CLIENT */
/*==============================================================*/
create table CLIENT (
ClNo SERIAL not null,
ClName VARCHAR(10) not null,
ClGender BOOL not null,
ClId CHAR(18) not null,
ClTel CHAR(11) not null,
ClAddress VARCHAR(50) not null,
constraint PK_CLIENT primary key (ClNo)
);
/*==============================================================*/
/* Index: CLIENT_PK */
/*==============================================================*/
create unique index CLIENT_PK on CLIENT (
ClNo
);
/*==============================================================*/
/* Table: RENT_FEE */
/*==============================================================*/
create table RENT_FEE (
RId INT4 not null,
FLease MONEY not null,
FOverDue MONEY null,
FDamage MONEY null,
FTotal MONEY not null,
constraint PK_RENT_FEE primary key (RId)
);
/*==============================================================*/
/* Index: RENT_FEE_PK */
/*==============================================================*/
create unique index RENT_FEE_PK on RENT_FEE (
RId
);
/*==============================================================*/
/* Table: RENT_PRICE */
/*==============================================================*/
create table RENT_PRICE (
CaId INT4 not null,
Price MONEY not null,
constraint PK_RENT_PRICE primary key (CaId)
);
/*==============================================================*/
/* Index: RENT_PRICE_PK */
/*==============================================================*/
create unique index RENT_PRICE_PK on RENT_PRICE (
CaId
);
/*==============================================================*/
/* Table: RENT_REG */
/*==============================================================*/
create table RENT_REG (
RId SERIAL not null,
ClNo INT4 not null,
CaId INT4 not null,
StartTime DATE not null,
ReturnTime DATE not null,
constraint PK_RENT_REG primary key (RId)
);
/*==============================================================*/
/* Index: RENT_REG_PK */
/*==============================================================*/
create unique index RENT_REG_PK on RENT_REG (
RId
);
/*==============================================================*/
/* Index: registration_FK */
/*==============================================================*/
create index registration_FK on RENT_REG (
ClNo
);
/*==============================================================*/
/* Index: Rent_FK */
/*==============================================================*/
create index Rent_FK on RENT_REG (
CaId
);
alter table RENT_FEE
add constraint FK_RENT_FEE_ENSURE_RENT_REG foreign key (RId)
references RENT_REG (RId)
on delete restrict on update restrict;
alter table RENT_PRICE
add constraint FK_RENT_PRI_ADOPT2_CAR foreign key (CaId)
references CAR (CaId)
on delete restrict on update restrict;
alter table RENT_REG
add constraint FK_RENT_REG_RENT_CAR foreign key (CaId)
references CAR (CaId)
on delete restrict on update restrict;
alter table RENT_REG
add constraint FK_RENT_REG_REGISTRAT_CLIENT foreign key (ClNo)
references CLIENT (ClNo)
on delete restrict on update restrict;
6.角色权限管理
6.1 角色权限管理表
对需求分析中角色管理进行设计,得到如下角色权限管理表:
数据库表 | 客户(R_Client) | 业务员(R_SalesMan) | 经理(R_Manager) | 系统管理员(R_Administrator) |
---|---|---|---|---|
客户表(CLIENT) | 查询、插入、修改 | 查询 | 查询 | 查询、插入、修改、删除 |
汽车信息表(CAR) | 查询 | 查询、插入、修改、删除 | 查询、插入、修改、删除 | 查询、插入、修改、删除 |
租赁价目表(RENT_PRICE) | 查询 | 查询 | 查询、插入、修改、删除 | 查询、插入、修改、删除 |
租赁登记表(RENT_REG) | 查询 | 查询、插入、修改 | 查询、插入、修改 | 查询、插入、修改、删除 |
租赁费用表(RENT_FEE) | 查询 | 查询、插入、修改 | 查询、插入、修改 | 查询、插入、修改、删除 |
6.2创建角色代码
CREATE ROLE "R_Client" WITH
LOGIN
CONNECTION LIMIT -1;
CREATE ROLE "R_SalesMan" WITH
LOGIN
CONNECTION LIMIT -1;
CREATE ROLE "R_Manager" WITH
LOGIN
CONNECTION LIMIT -1;
CREATE ROLE "R_Administrator" WITH
LOGIN
CONNECTION LIMIT -1;
6.3权限控制代码
--客户权限管理
GRANT SELECT,INSERT,UPDATE ON CLIENT TO "R_Client";
GRANT SELECT ON CAR TO "R_Client";
GRANT SELECT ON RENT_PRICE TO "R_Client";
GRANT SELECT ON RENT_REG TO "R_Client";
GRANT SELECT ON RENT_FEE TO "R_Client";
--业务员权限管理
GRANT SELECT ON CLIENT TO "R_SalesMan";
GRANT SELECT,INSERT,UPDATE,DELETE ON CAR TO "R_SalesMan";
GRANT SELECT ON RENT_PRICE TO "R_SalesMan";
GRANT SELECT,INSERT,UPDATE ON RENT_REG TO "R_SalesMan";
GRANT SELECT,INSERT,UPDATE ON RENT_FEE TO "R_SalesMan";
--经理业务管理
GRANT SELECT ON CLIENT TO "R_Manager";
GRANT SELECT,INSERT,UPDATE,DELETE ON CAR TO "R_Manager";
GRANT SELECT,INSERT,UPDATE,DELETE ON RENT_PRICE TO "R_Manager";
GRANT SELECT,INSERT,UPDATE ON RENT_REG TO "R_Manager";
GRANT SELECT,INSERT,UPDATE ON RENT_FEE TO "R_Manager";
--系统管理员业务管理
GRANT SELECT,INSERT,UPDATE,DELETE ON CLIENT TO "R_Administrator";
GRANT SELECT,INSERT,UPDATE,DELETE ON CAR TO "R_Administrator";
GRANT SELECT,INSERT,UPDATE,DELETE ON RENT_PRICE TO "R_Administrator";
GRANT SELECT,INSERT,UPDATE,DELETE ON RENT_REG TO "R_Administrator";
GRANT SELECT,INSERT,UPDATE,DELETE ON RENT_FEE TO "R_Administrator";
可以通过查询的方式查看这些角色的权限作初步的验证.查询语句如下
--以查询客户的权限为例
select * from information_schema.table_privileges where grantee='R_Client';
由上图可见,R_Client
确实对上述的5个表拥有正确的权限.接下来进一步测试权限.
7.测试
7.1创建用户
使用如下代码创建用户
CREATE USER "ClientUser" WITH
LOGIN
CONNECTION LIMIT -1
IN ROLE "R_Client"
PASSWORD '123456';
CREATE USER "SalesManUser" WITH
LOGIN
CONNECTION LIMIT -1
IN ROLE "R_SalesMan"
PASSWORD '123456';
CREATE USER "ManagerUser" WITH
LOGIN
CONNECTION LIMIT -1
IN ROLE "R_Manager"
PASSWORD '123456';
CREATE USER "AdministratorUser" WITH
LOGIN
CONNECTION LIMIT -1
IN ROLE "R_Administrator"
PASSWORD '123456';
7.2插入数据
插入数据如下
INSERT INTO CLIENT VALUES(1,'张三',TRUE,'330225199910101234','12345678910','浙江宁波');
INSERT INTO CAR VALUES(1,'浙A11111','奥迪A6','白色',TRUE);
INSERT INTO RENT_REG VALUES(1,1,1,CURRENT_DATE, CURRENT_DATE);
INSERT INTO RENT_FEE VALUES(1,100,0,0,100);
INSERT INTO RENT_PRICE VALUES(1,100);
7.3用户权限测试
以客户为例.在命令行输入如下指令,并输入密码,登录数据库,运行结果如下:
正确连接数据库,现在对数据进行操作
-
查询用户信息表
输入指令select * from client;
,显示结果
-
修改用户信息表
输入指令update client set cltel = '10987654321' where cltel='12345678910';
,并显示结果.可见修改成功,数据已经被修改
-
查询租赁信息表
输入指令select * from rent_reg;
,显示结果
-
修改租赁信息表
输入指令update rent_reg set rid = 2 where rid=1;
,显示结果
因为客户对租赁信息是没有修改权限的,所以不报错
经理和业务员主要区别在对租赁价格表的修改,删除,增加上,通过两者对比可以更好得展现权限的作用.
8.备份和恢复数据库
8.1使用GUI备份和恢复
8.1.1 备份
具体步骤:选中需要备份的数据库–>右键菜单选中备份–>填写文件名和格式如下图所示–>点击备份(备份文件可见附件)
备份完成会弹出如下对话框
8.1.2 恢复
选中需要恢复的数据库–>右键菜单选中还原中–>选择恢复所需的备份文件–>点击恢复
重新创建了一个数据库CarRentDB2
,进行恢复,完成后弹出如下对话框
同时可以看到右边的资源管理器中的CarRentDB2
已经生成相应的表
同样的,对于单个schame和单个表也可以采用类似的方式,通过菜单栏备份和恢复
8.2 使用pg_dump工具备份
8.2.1 备份整个数据库
具体命令如下
pg_dump -U AdministratorUser -d CarRentDB > E:\db.sql
8.2.2 备份Schame
具体命令如下
pg_dump -U AdministratorUser -d CarRentDB -n public > E:\schema.sql
8.2.3 备份单个表
具体命令如下
pg_dump -U AdministratorUser -t rent_price CarRentDB > E:\price.sql
打开文件资源管理器可以看到对应路径下已经生成对应的文件
9.存在问题
第一个问题:powerdesigner不允许使用重复相同的存储代码(概念模型可以,但是逻辑模型不行),所以不得步修改概念模型.使用的方法是先使用不一样的存储代码,生成逻辑模型后,然后删除多出的属性,然后会弹出重新指定标识符(外键)的框,然后选为之前的标识符,最后修改原先的标识符.但是最后考虑了两个表的关系,发现改变标识符效果更好,可以使用标识符依赖.
第二个问题:生成的逻辑模型不能生成物理模型,因为存在循环依赖.但是感念模型可以.这个没有解决.不清楚内部的错误在哪里.预计是概念模型中有部分错误.
第三个问题:有时候服务器莫名登不上去,一会儿是密码错误,一会儿是服务器连接错误,还出现数据库不存在的情况.但是重启一段时间后就没问题了,浪费了很多时间.
第四个问题:在使用pg_dump备份时会查找不到所需要的序列,但是在pgAdmin中是可以查找到对应序列,并执行其报错语句可以有正确的返回结果.原因是序列的所有者是超级用户,但是AdministratorUser并没有查询这个序列的权限,所以在备份时无法查询到对应的数据.但是构建表后序列已经连接在关系表上,无法修改主属,所以只能增加AdministratorUser的权限.