数据库-库表设计 【分享一些库表设计经验】
本文的核心内容:记录积累一些库表设计方案与技巧
数据库表的菜单【分类】设计:如省市关联、图书的一、二级分类。
数据库表设计之购物车,利用Session暂时存储购物车信息。
一:数据库表的菜单【分类】设计:如省市关联、图书的一、二级分类
BookType 一级分类: 少儿、外语、计算机
BookClass 二级分类: 少儿[0-2岁、3-6岁、7-10岁、11-14岁、儿童文学]
外语[英语、日语、韩语、俄语、德语]
计算机[计算机理论、计算机考试、数据库、人工智能、程序设计]
BookInf 图书详情 : 图书信息的详细字段。。。
基于以上关系:我们建表有两种方法
①:建立三张表 一级分类表,二级分类表、图书详情表
一级分类ID->作为二级分类的外键
二级分类ID->作为图书详情的外键
这一种依赖外键,实体模型也比较简单。(不再过多描述)
查询语句:可以采用 left join on 或者 等值连接 将二级分类的外键与一级分类的主键等值连接即可查询。
②:建立两张表 一级分类和二级分类合并成一张表
图书详情表(引用TypeID为外键)
TypeID 指一级二级分类的ID(唯一标识、主键) 序列自增从1开始。
TypeName 指一级二级分类的名字
ParentID 指二级分类所属一级分类TypeID (若为一级分类则填”0”与二级分类加以区分)
countNumber 指一级图书包含二级图书的个数
二级分类所包含详细图书的个数
数据库查询一级分类信息的SQL
select typeid,typename,parentid,countnumber
from t_booktype where parentid='0'
数据查询二级分类信息(利用表的自连接)
select child.typeid,child.typename,
child.parentid,child.countnumber
from t_booktype child ,t_booktype parent
where child.parentid=parent.typeid
二:购物车模块的库表设计
在电商软件,必不可少的模块就是购物车。
我分享两种设计方法:
①:维护一张购物车表,以用户ID为外键
一个用户一个购物车,用户注册成功的同时,为用户在购物车表内维护一个专属于用户的购物车。(根据我以前学到的知识,这一步可以为用户表创建Insert触发法器,当用户注册成功[触发器将用户ID作为外键插入购物车表],用户即拥有了唯一的购物车)
T_Car
字段 |
类型 |
说明 |
Car_ID |
Varchar2(36) |
购物车编号 主键 |
User_ID |
Varchar2(36) |
外键 用户唯一标识 |
Car_Status |
Varchar2(4) |
购物车状态 |
T_Shop_Item
字段 |
类型 |
说明 |
Shop_item_ID |
Varchar2(36) |
购物项编号 主键 |
Car_ID |
Varchar2(36) |
购物车编号 外键 |
Product_ID |
Varchar2(36) |
商品编号 外键 |
Count |
Number(4) |
数量 |
Price |
number(8,2) |
价格 |
ProductName |
Varchar(30) |
商品名 |
这么实现购物车的弊端:①:非该网站的注册用户无法将商品加入购物车。这与现实的情况不符合。一般我们访问某宝,某东,我们可以以游客的方式将商品加入购物车,直到下订单、付款时才要求我们必须登录。②:每个用户维护一下购物车似乎不太明智,顾客将商品加入购物车到下订单,完成交易,这一需求对数据库更改频繁。
②:所有用户共用一个”购物车”
我们可以直接以用户ID为标识,区分购物车商品所属的用户。
T_Shop_Item
字段 |
类型 |
说明 |
Shop_item_ID |
Varchar2(36) |
购物项编号 主键 |
User_ID |
Varchar2(36) |
用户编号 外键 |
ProductID |
Varchar2(36) |
商品编号 外键 |
Count |
Number(4) |
数量 |
Price |
number(8,2) |
价格 |
ProductName |
Varchar(30) |
商品名 |
即使减少了一张购物车表,但是这表还需要用户登录才能记录用户添加商品情况。
③:利用Session暂时存储购物车内的东西
[用户不登录就能添加商品到购物车;用户登录状态将Session中的信息存入非关系型数据库、关系型数据库。将购物车内的东西持久化存储]
明确一点:Session -> 一次会话有效(在用户不关闭浏览器的前提下,默认存在30分钟;用户关闭浏览器再次打开后,未登录用户的购物车将清空。)
解决如何用Session存储购物车内信息。
第一个难点:那么如何准确区分不同的商品? (自然是商品ID)
第二个难点:那么如何准确标记一个进入购物车的商品? (只有商品ID是不行的)
商品ID,通过商品ID,我们可以查询到商品详情。(价格、名称等等)
同一商品的购买数量。这一信息是不存在于商品详情的。【重点,不能忽略】
这两个信息必须存储。于是我想到Map(两个原因)。
①:存储两个值
Map<String,Integer> map=new HashMap<String,Integer>();
key存储 商品ID, value存储 商品数量(购买数量)
②:保证商品ID(键)的唯一性
Map的特点:键唯一,值可以重复。我们以商品ID为键,这样就可以保证商品的唯一性。
我们再将map存入Session中就可以了。
当用户添加商品时,只需先从Session中取出map,迭代遍历判断key是否已经存在,若存在取value值加1;若不存在则将商品ID作为key,value数量默认为1,Put进map。
当用户(未登录)查看购物车时,只需从Session中取商品ID和数量,就可以显示购车内商品的详细信息,计算购物车内的商品总价格。
这种存储方式简化了添加商品进入购物车和删除购物车里商品的操作。但是却不得不再次封装一个Map对象将购物车详情页面的信息存储进去,以供购物车展示页面显示数据。
(这是我第一次考虑的存储方案,写到查看购物车详情页面才发现不合理之处。)
改进版本:
Map <String,Goods> map=new HashMap<String,Goods> ();
Key ->商品id
Value->购物车页面需要展示的商品详情(商品名、商品ID、商品数量、商品价格等)
核心:value值维护不再是一个商品数量,而是我们封装的模拟购物车实体对象
JSP页面的效果图
源代码:添加商品的Action
//添加商品Action
public String addToCar() throws Exception{
//尝试从Session取出购物车
ValueStack vs=ActionContext.getContext().getValueStack();
Map<String,Goods> car=(Map<String,Goods>)vs.findValue("#session.car");
BookService service=new BookServiceImpl();
if(car==null){
//判断购物车是否存在
//不存在则创建,将用户添加的商品加入Map 存入Session
Map<String,Goods> map=new HashMap<String,Goods>();
//查询数据将商品详情查询出出来,把我们感兴趣的属性封装到Goods实体中
Book book=service.getSingleBook(bookid);
Goods goods=new Goods();
goods.setBookid(book.getBookid());
goods.setCount(1);
goods.setPrice(book.getPrice());
goods.setCurrentprice(book.getCurrentprice());
goods.setProductname(book.getProductname());
map.put(bookid, goods);
vs.setValue("#session.car", map);
}else{
//判断用户添加的商品是否已经存在于购物车里
//若存在根据key取出Goods->修改商品选购的数量
//不存在则是首次添加,数量默认为1 ,将商品Put入map
if(car.containsKey(bookid)){
Goods product=car.get(bookid);
product.setCount(product.getCount()+1);
}else{
Book book=service.getSingleBook(bookid);
Goods goods=new Goods();
goods.setBookid(book.getBookid());
goods.setCount(1);
goods.setPrice(book.getPrice());
goods.setCurrentprice(book.getCurrentprice());
goods.setProductname(book.getProductname());
car.put(bookid, goods);
}
}
return Action.SUCCESS;
}