任务八 综合案例

1.商城案例表设计

通过对商城项目的部分表关系进行分析,完成数据库表的设计

1.1 表关系分析

01.jpg

1.2 建库,建表

  1. 创建名为 store的数据库, 对应商城项目
  1. create database db6 character set utf8;
  1. 创建用户表
  1. CREATE TABLE user (
  2. uid varchar(32) PRIMARY KEY, -- 用户ID
  3. username varchar(20) , -- 用户名
  4. password varchar(20) , -- 密码
  5. telephone varchar(20) , -- 电话
  6. birthday date , -- 生日
  7. sex varchar(10) -- 性别
  8. );
  1. INSERT INTO USER VALUES
  2. ('001','渣渣辉','123456','13511112222','2015-11-04','男'),
  3. ('002','药水哥','123456','13533334444','1990-02-01','男'),
  4. ('003','大明白','123456','13544445555','2015-11-03','男'),
  5. ('004','长海','123456','13566667777','2000-02-01','男'),
  6. ('005','乔杉','123456','13588889999','2000-02-01','男');
  1. 创建订单表
  1. CREATE TABLE orders (
  2. oid varchar(32) PRIMARY KEY, -- 订单id
  3. ordertime datetime , -- 下单时间
  4. total double , -- 总金额
  5. name varchar(20), -- 收货人姓名
  6. telephone varchar(20) , -- 电话
  7. address varchar(30) , -- 地址
  8. state int(11) , -- 订单状态
  9. uid varchar(32), -- 外键字段 对应用户表id
  10. CONSTRAINT ofk_0001 FOREIGN KEY (uid) REFERENCES user (uid)
  11. );
  1. -- 插入一条订单数据
  2. INSERT INTO orders
  3. VALUES('order001','2019-10-11',5500,'乔杉','15512342345','皇家洗浴',0,'001');
  1. 创建商品分类表
  1. CREATE TABLE category (
  2. cid varchar(32) PRIMARY KEY,
  3. cname varchar(20)
  4. );
  1. INSERT INTO `category` VALUES ('1','手机数码'),('2','电脑办公'),('3','运动鞋服'),('4','图书音像');
  1. 创建商品表
  1. CREATE TABLE product (
  2. pid varchar(32) PRIMARY KEY, -- 商品id
  3. pname varchar(50) , -- 商品名称
  4. price double, -- 商品价格
  5. pdesc varchar(255), -- 商品描述
  6. pflag int(11) , -- 商品状态 1 上架 ,0 下架
  7. cid varchar(32) , -- 外键对应 分类表id
  8. KEY sfk_0001 (cid),
  9. CONSTRAINT sfk_0001 FOREIGN KEY (cid) REFERENCES category (cid)
  10. );
  1. INSERT INTO `product` VALUES
  2. ('1','小米6',2200,'小米 移动联通电信4G手机 双卡双待',0,'1'),
  3. ('2','华为Mate9',2599,'华为 双卡双待 高清大屏',0,'1'),
  4. ('3','OPPO11',3000,'移动联通 双4G手机',0,'1'),
  5. ('4','华为荣耀',1499,'3GB内存标准版 黑色 移动4G手机',0,'1'),
  6. ('5','华硕台式电脑',5000,'爆款直降,满千减百',0,'2'),
  7. ('6','MacBook',6688,'128GB 闪存',0,'2'),
  8. ('7','ThinkPad',4199,'轻薄系列1)',0,'2'),
  9. ('8','联想小新',4499,'14英寸超薄笔记本电脑',0,'2'),
  10. ('9','李宁音速6',500,'实战篮球鞋',0,'3'),
  11. ('10','AJ11',3300,'乔丹实战系列',0,'3'),
  12. ('11','AJ1',5800,'精神小伙系列',0,'3');
  1. 订单项表 (中间表)
  1. -- 订单项表
  2. CREATE TABLE orderitem (
  3. itemid VARCHAR(32) PRIMARY KEY, -- 订单项ID
  4. pid VARCHAR(32), -- 外键 对应商品表 id
  5. oid VARCHAR(32), -- 外键 对应订单表 id
  6. KEY fk_0001 (pid),
  7. KEY fk_0002 (oid),
  8. CONSTRAINT fk_0001 FOREIGN KEY (pid) REFERENCES product (pid),
  9. CONSTRAINT fk_0002 FOREIGN KEY (oid) REFERENCES orders (oid)
  10. );
  1. -- 向中间表中插入两条数据
  2. INSERT INTO orderitem VALUES('item001','1','order001');
  3. INSERT INTO orderitem VALUES('item002','11','order001');

2.环境搭建

2.1 项目结构

  1. com.lagou.app 测试包 用于对DAO代码进行测试
  2. com.lagou.dao dao 数据访问层,包含所有对数据库的相关操作的类
  3. com.lagou.entity 实体包 保存根据数据库表 对应创建的JavaBean
  4. com.lagou.utils 工具包

03.jpg

2.2 导入所需Jar包

  1. 我们只需要导入myjar仓库到项目中就可以了

04.jpg

2.3 导入配置文件及工具类

05.jpg

3.JavaBean类创建

3.1 设计用户与订单

3.1.1 一对多关系分析

  • 在Java一对多的数据关系中,需要遵循以下设计原则:
    1. Java类的名称 = 实体表的名称
    2. Java类的属性 = 实体表的字段
    3. Java类的一个对象 = 表的一行记录
    4. 外键关系 = 引用配置
  • 一个用户拥有多个订单,所以 用户是一的一方, 订单是多的一方

06.jpg

3.1.2 User类

  1. /**
  2. * 用户表 对应 User类
  3. * `uid` VARCHAR(32) NOT NULL,
  4. * `username` VARCHAR(20) DEFAULT NULL,
  5. * `password` VARCHAR(20) DEFAULT NULL,
  6. * `telephone` VARCHAR(20) DEFAULT NULL,
  7. * `birthday` DATE DEFAULT NULL,
  8. * `sex` VARCHAR(10) DEFAULT NULL,
  9. * */
  10. public class User {
  11. private String uid;
  12. private String username;
  13. private String password;
  14. private String telephone;
  15. private String birthday;
  16. private String sex;
  17. //提供 get set toString方法
  18. }

3.1.3 Orders类

  1. /**
  2. * 订单表
  3. * `oid` VARCHAR(32) NOT NULL,
  4. * `ordertime` DATETIME DEFAULT NULL,
  5. * `total` DOUBLE DEFAULT NULL,
  6. * `name` VARCHAR(20) DEFAULT NULL,
  7. * `telephone` VARCHAR(20) DEFAULT NULL,
  8. * `address` VARCHAR(30) DEFAULT NULL,
  9. * `state` INT(11) DEFAULT NULL,
  10. * `uid` VARCHAR(32) DEFAULT NULL,
  11. *
  12. * */
  13. public class Orders {
  14. private String oid; //订单号
  15. private String ordertime; //下单时间
  16. private double total; //订单的总金额
  17. private String name; //收货人姓名
  18. private String telephone; //收货人电话
  19. private String address; //收货人地址
  20. private int state; //订单状态 1 代表已支付 , 0 代表未支付
  21. //订单属于哪个用户呢 ?
  22. //提供 get set toString方法
  23. }

3.1.4 Orders类设计分析

  • 第一种方式

    • 根据两张表关系的描述 我们可以在 订单类中 添加一个uid 成员变量,表示订单属于哪个用户java private String uid;

    • 但是这样设计会存在一些问题,比如 我要查询的是订单是属于哪个用户的用户名 ? 但是我们只有一个uid

  • 第二种方式
    • Java类表示一对多关系,可以在多的一方添加一个成员变量,这个成员变量的类型 就是一的一方的类型.
    • 再在订单表中 添加一个 User对象,User对象中 ,保存该订单关联的用户的所有信息java private String uid; private User user;

3.1.4 修改Orders类

  1. public class Orders {
  2. private String oid; //订单号
  3. private String ordertime; //下单时间
  4. private double total; //订单的总金额
  5. private String name; //收货人姓名
  6. private String telephone; //收货人电话
  7. private String address; //收货人地址
  8. private int state; //订单状态 1 代表已支付 , 0 代表未支付
  9. //订单属于哪个用户呢 ?
  10. private String uid; //表示外键
  11. private User user; //用来保存订单对应的详细的用户信息
  12. //提供 get set toString方法
  13. }

3.2 设计商品与分类

分类与商品 同样是一对多关系, 我们可以在多的一方进行操作 添加一个成员变量 类型是一的一方的类型
07.jpg

3.2.1 Category类

  1. public class Category {
  2. private String cid;
  3. private String cname;
  4. //提供 get set toString方法
  5. }

3.2.2 Product类

  1. public class Product {
  2. private String pid;
  3. private String pname;
  4. private double price;
  5. private String pdesc;
  6. private int pflag; //是否上架 1 上架 ,0 下架
  7. private String cid; //外键 对应分类表主键
  8. private Category category; //用于保存Category的详细数据
  9. //提供 get set toString方法
  10. }

3.3 设计订单项

3.3.1 多对多关系分析

商品与订单是多对多关系, 一个订单上可以有多个商品, 一个商品可以出现在多个订单中.

多对多建表原则 需要一张中间表,中间表中至少有两个字段,作为中间表的外键分别指向另外两张表的主键
11.jpg

3.3.2 创建OrderItem

  1. /**
  2. * 订单项表(中间表)
  3. * `itemid` VARCHAR(32) NOT NULL,
  4. * `pid` VARCHAR(32) DEFAULT NULL,
  5. * `oid` VARCHAR(32) DEFAULT NULL,
  6. *
  7. * */
  8. public class OrderItem {
  9. //订单项 指的是中间表中的一条数据
  10. private String itemid; //订单项的id
  11. private String pid; //外键 指向商品表主键
  12. private String oid; //外键 指向订单表的主键
  13. private Product product;//订单项内部的商品详细信息
  14. private Orders orders;//订单项属于哪个订单
  15. }

4.编写DAO类

4.1 UserDao

  • 需求一: 编写一个注册用户的方法,接收的参数是一个User对象
  • 需求二: 编写一个 用户登录的方法,接收的参数是 用户名 和密码, 返回值是User对象

4.1.1 编写UserDao

  1. public class UserDao {
  2. /**
  3. * 注册用户
  4. * */
  5. public int register(User user) throws SQLException {
  6. //1.获取QueryRunner
  7. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  8. //2.编写SQL
  9. String sql = "insert into user values(?,?,?,?,?,?)";
  10. Object[] param = {user.getUid(), user.getUsername(), user.getPassword(),
  11. user.getTelephone(), user.getBirthday(), user.getSex()};
  12. //3.执行插入操作
  13. int update = qr.update(sql,param);
  14. //4.返回受影响的行数
  15. return update;
  16. }
  17. /**
  18. * 用户注册
  19. * */
  20. public User login(String username , String password) throws SQLException {
  21. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  22. String sql = "select * from user where username = ? and password = ?";
  23. //返回的是一个User对象 使用BeanHandler将结果集的第一条和数据封装到一个Javabean中
  24. User user = qr.query(sql, new BeanHandler<User>(User.class), username, password);
  25. return user;
  26. }
  27. }

4.1.2 测试注册与登录功能

  1. public class TestUserDao {
  2. //创建UserDao
  3. UserDao userDao = new UserDao();
  4. //测试注册功能
  5. @Test
  6. public void testRegister() throws SQLException {
  7. //1. 创建User对象
  8. User user = new User();
  9. //2. 对User对象进行赋值
  10. user.setUid(UUIDUtils.getUUID());
  11. user.setUsername("大郎");
  12. user.setPassword("654321");
  13. user.setTelephone("15052005200");
  14. user.setSex("男");
  15. user.setBirthday(DateUtils.getDateFormart());
  16. //3.执行注册
  17. int register = userDao.register(user);
  18. //4.判断注册是否成功
  19. if(register > 0){
  20. System.out.println("注册成功,欢迎您: " + user.getUsername());
  21. }else{
  22. System.out.println("注册失败! !");
  23. }
  24. }
  25. //测试登录功能
  26. @Test
  27. public void testLogin() throws SQLException {
  28. //调用UserDao的 login方法,传入用户名密码
  29. User user = userDao.login("大郎", "654321");
  30. //判断user不为空 登录成功
  31. if(user != null){
  32. System.out.println(user.getUsername() +" 欢迎您!");
  33. }else{
  34. System.out.println("用户名或者密码错误! !");
  35. }
  36. }
  37. }

4.2 ProductDao

  • 需求1: 根据商品ID 获取商品名称 ,商品价格 以及商品所属分类的名称
    • 参数 pid, 返回值 product对象
  • 需求2: 根据分类ID 获取商品分类信息
    • 参数 cid , 返回值 category对象
  • 需求3: 查询指定分类ID 下的商品个数
    • 参数 cid , 返回值 int类型 商品个数
  • 需求4: 查询指定分类ID 下的所有商品信息
    • 参数分类ID ,返回值 List集合 集合中保存商品对象

4.2.1 编写 ProductDao

  1. public class ProductDao {
  2. //1.根据商品ID 获取商品名称 ,商品价格 以及商品所属分类的名称
  3. public Product findProductById(String pid) throws SQLException {
  4. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  5. String sql = "select * from product where pid = ?";
  6. Product product = qr.query(sql, new BeanHandler<Product>(Product.class), pid);
  7. //调用 findCategoryById()方法, 传递外键cid 获取商品对应 的分类信息
  8. Category category = findCategoryById(product.getCid());
  9. //将category保存到商品对象中
  10. product.setCategory(category);
  11. return product;
  12. }
  13. //2.根据分类ID 获取商品分类信息
  14. public Category findCategoryById(String cid) throws SQLException {
  15. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  16. String sql = "select * from category where cid = ?";
  17. Category category = qr.query(sql, new BeanHandler<Category>(Category.class),cid);
  18. return category;
  19. }
  20. //3.查询指定分类ID 下的商品个数
  21. public int getCount(String cid) throws SQLException {
  22. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  23. String sql = "select count(*) from product where cid = ?";
  24. //获取的单列数据 ,使用ScalarHandler 封装
  25. Long count = (Long)qr.query(sql,new ScalarHandler<>(),cid);
  26. //将Lang类型转换为 int 类型,并返回
  27. return count.intValue();
  28. }
  29. //4.查询指定分类下的所有商品信息
  30. public List<Product> findProductByCid(String cid) throws SQLException {
  31. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  32. String sql = "select * from product where cid = ?";
  33. //查询结果是一个List集合, 使用BeanListHandler 封装结果集
  34. List<Product> list = qr.query(sql, new BeanListHandler<Product>(Product.class), cid);
  35. return list;
  36. }
  37. }

4.2.2 测试 ProductDao

  1. public class TestProductDao {
  2. ProductDao productDao = new ProductDao();
  3. //1.测试 根据商品ID 获取商品名称 ,商品价格 以及商品所属分类的名称
  4. @Test
  5. public void testFindProductById() throws SQLException {
  6. Product product = productDao.findProductById("1");
  7. System.out.println("商品名称: "+product.getPname()+ ", 商品价格: " + product.getPrice() +
  8. ", 商品所属分类: "+ product.getCategory().getCname());
  9. }
  10. //2.测试 查询指定分类ID下的商品数
  11. @Test
  12. public void testGetCount() throws SQLException {
  13. //查询 cid为3的分类下有多少个商品
  14. int count = productDao.getCount("3");
  15. System.out.println("分类ID为3的分类下商品个数: " + count);
  16. }
  17. //3.测试 查询指定分类下的所有商品信息
  18. @Test
  19. public void testFindProductByCid() throws SQLException {
  20. //查询cid为 2的分类下 所有的商品信息
  21. List<Product> list = productDao.findProductByCid("2");
  22. for (Product product : list) {
  23. System.out.println(product);
  24. }
  25. }
  26. }

4.3 OrdersDao

4.3.1 多对一分析

OrderItem表与Orders表的关系是 多对一
09.jpg
之前我们一直是在描述一对多,那么我们再反向描述一下 多对一

方式是在Orders中应该有一个 集合用来保存订单中的订单项信息
10.jpg
在Orders类中添加 订单项的集合

  1. //该订单中有多少订单项
  2. List<OrderItem> orderItems = new ArrayList<OrderItem>();
  3. public List<OrderItem> getOrderItems() {
  4. return orderItems;
  5. }
  6. public void setOrderItems(List<OrderItem> orderItems) {
  7. this.orderItems = orderItems;
  8. }

4.3.2 创建OrdersDao

  • 需求1: 获取 uid为 001 的用户的所有订单信息
  • 参数 uid, 返回值 LIst 订单集合
  • 需求2: 获取订单编号为 order001的订单中的所有商品信息
    • 参数 oid, 返回值List 商品集合 ```sql — 获取订单编号为: order001的订单中的所有商品信息

— 1.查询订单项表中 oid是order001的 所有商品信息 SELECT oi.pid FROM orderitem oi WHERE oid = ‘order001’;

— 2.将上面的查询语句作为in函数的条件, 查询product表 SELECT * FROM product WHERE pid IN (SELECT oi.pid FROM orderitem oi WHERE oid = ‘order001’);

  1. ```java
  2. public class OrdersDao {
  3. //需求1: 获取 uid为 001 的用户的所有订单信息
  4. public List<Orders> findAllOrders(String uid) throws SQLException {
  5. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  6. String sql = "select * from orders where uid = ?";
  7. //一个用户所有的订单信息
  8. List<Orders> ordersList = qr.query(sql, new BeanListHandler<Orders>(Orders.class), uid);
  9. return ordersList;
  10. }
  11. //需求2: 获取订单编号为 order001的订单中的所有商品信息
  12. public List<Product> findOrderById(String oid) throws SQLException {
  13. QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
  14. //1.查询订单项表 获取订单项表中 订单ID为order001的数据
  15. String sql = "SELECT pid FROM orderitem WHERE oid = ? ";
  16. //2.查询的结果是 多条订单项数据
  17. List<OrderItem> list = qr.query(sql, new BeanListHandler<OrderItem>(OrderItem.class), oid);
  18. //3.创建集合保存商品信息
  19. List<Product> productList = new ArrayList<>();
  20. ProductDao productDao = new ProductDao();
  21. //4.遍历订单项集合 获取Pid
  22. for (OrderItem orderItem : list) {
  23. //4.1从orderitem中获取 pid
  24. String pid = orderItem.getPid();
  25. //4.2 调用productDao
  26. Product product = productDao.findProductById(pid);
  27. //4.3 保存到集合
  28. productList.add(product);
  29. }
  30. //返回 订单中对应的商品信息
  31. return productList;
  32. }
  33. }

4.3.3 测试OrdersDao

  1. public class TestOrderDao {
  2. OrdersDao ordersDao = new OrdersDao();
  3. //1.获取 uid为 001 的用户的所有订单信息
  4. @Test
  5. public void testFindAllOrders() throws SQLException {
  6. List<Orders> allOrders = ordersDao.findAllOrders("001");
  7. //遍历打印订单信息
  8. for (Orders order : allOrders) {
  9. System.out.println(order);
  10. }
  11. }
  12. //测试 获取订单编号为: order001的订单中的所有商品信息
  13. @Test
  14. public void testFindOrderById() throws SQLException {
  15. List<Product> list = ordersDao.findOrderById("order001");
  16. System.out.println("订单编号为order001中的商品有: ");
  17. for (Product product : list) {
  18. System.out.println(product);
  19. }
  20. }
  21. }