大数据正式25

大数据正式25

  • EasyMall商品删除模块

    • 设计
      1. 在商品列表界面的商品后边添加删除按钮
      2. 点击删除按钮,然后访问ManageDelProdServlet
      3. 调用Service删除相应的产品
      4. 调用dao层真正的删除
    • 可能出现的问题---【【更新丢失】】

      1. 两个管理员删除同一种类的最后两个商品【商品可以删除,但是种类没删除掉】
      2. 原因:分别进入的事务判断的都是对的(>1),然后各自删完商品后,种类应该随着删除掉,但是两次都是因为大于1进的,所以这个地方有纰漏
      3. 问题的本质:两个并发的事务,基于同一个查询结果进行更新操作,然后出现没有更新的现象
      4. 图解
      5. 例子
        1. 秒杀抢购
          • 当同一时刻有大量的用户抢购时,抢购事务将会各自执行,但是数据库的更新会出现乱子
          • 图解
        2. 重复充值
          • 网络中断或延迟:银行反复向服务器发送确认请求,当多次的请求同时开启事务时,将会发生更新丢失现象(相同的加钱操作执行了两次)。
          • 图解
      6. 解决方案

        1. 将数据库的隔离级别设置为Serializable【产生死锁-->>结束一方,执行另一方】
        2. 悲观锁解决方案
          1. 数据库中不存在这个锁----这是解决方案的名称
          2. 每次查询认为比较“悲观”添加排他锁

            select * from table for update;#排它锁for update
            
          3. 特点:排斥其他事务
          4. 应用场景:更新的,查询少
        3. 乐观锁解决方案

          1. 数据库中不存在这个锁----这是解决方案的名称
          2. 乐观的认为,每次查询都不会造成更新的丢失,检测更新的丢失来进行相应的处理

            1. 得到预料的值:select 
            
            2. select * from table and 检测的字段=预料的值;#乐观锁(判断理想中的条件是否成立)
            
            3. 判断是否要回滚操作
            
          3. 特点:可能造成一个事务循环【当自己的事务进行时又来一个事务】
          4. 应用场景:查询的,更新少
        4. EasyMall的解决方案

          1. 问题点:查询该种类的剩余商品
          2. 解决:查询该种类的剩余商品的时候添加悲观锁

            public List findProdsByCategoryId(int category_id) {
            
                    List prod_list = new ArrayList();
                    try {
                        // 查询数据库,并把每一条记录包装成Prod对象存入prod_list列表中
                        conn = MySqlUtils.getConn();
                        stat = conn
                                .prepareStatement("select * from prod inner join prod_category where prod.prodCategory_id=prod_category.id and prod_category.id=? for update");//悲观锁解决方案(for update)
                        stat.setInt(1, category_id);
                        rs = stat.executeQuery();
                        while (rs.next()) {
                            Prod prod = new Prod();
                            prod.setId(rs.getInt(1));
                            prod.setName(rs.getString(2));
                            prod.setPnum(rs.getInt(4));
                            prod.setDescription(rs.getString(7));
                            prod.setImgurl(rs.getString(5));
                            prod.setPrice(rs.getDouble(3));
                            prod.setProdCategory_id(rs.getInt(6));
                            prod.setProdCategory(new ProdCategory(rs.getString(8), rs
                                    .getString(9)));
                            prod_list.add(prod);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    } finally {
                        MySqlUtils.close(null, stat, rs);
                    }
                    return prod_list;
            
                }
            

商品删除具体实现

  • 效果图展示
  • 代码

    • 页面

      • manageProdList.jsp

        <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
        <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
        
        
        
        
        
        
        
        
            

        商品管理

        添加商品
        商品图片 商品id 商品名称 商品种类 商品单价 库存数量 描述信息 删除
        ${prod.id } ${prod.name } ${prod.prodCategory.name } ${prod.price } ${prod.description } 删除
    • web

      • ManageProdDelServlet

        package com.easymall.web;
        
        import java.io.IOException;
        
        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        
        import com.easymall.factory.BasicFactory;
        import com.easymall.service.ProdService;
        
        @SuppressWarnings("serial")
        public class ManageProdDelServlet extends HttpServlet {
        
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                this.doPost(request, response);
        
            }
        
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                // 获取参数--商品的id
                int id = Integer.parseInt(request.getParameter("id"));
                // 通过id 删除对应的商品
                ProdService service = BasicFactory.getFactory().getObj(
                        ProdService.class);
                service.delProd(id);
                // 返回商品列表界面
                response.getWriter().write("删除成功!即将返回。。。");
                response.setHeader("refresh", "2;url=ManagerProdListServlet");
            }
        
        }
        
    • service

      • ProdService

        package com.easymall.service;
        
        import java.util.List;
        
        import com.easymall.domain.Prod;
        
        public interface ProdService {
            /**
             * 添加一个产品
             * 
             * @param prod
             */
            public void addProd(Prod prod);
        
            /**
             * 查询所有的商品
             * 
             * @return 查询所有的商品
             */
            public List findProdList();
        
            /**
             * 通过id更新商品的pnum
             * 
             * @param id
             * @param pnum
             */
            public void upDatePunm(int id, int pnum);
        
            /**
             * 通过id删除相应的产品
             * @param id
             */
            public void delProd(int id);
        }
        
      • ProdServiceImpl

        package com.easymall.service;
        
        import java.util.List;
        
        import com.easymall.dao.ProdDao;
        import com.easymall.domain.Prod;
        import com.easymall.domain.ProdCategory;
        import com.easymall.factory.BasicFactory;
        import com.easymall.utils.TransactionManager;
        
        public class ProdServiceImpl implements ProdService {
            private ProdDao prodDao = BasicFactory.getFactory().getObj(ProdDao.class);
        
            public void addProd(Prod prod) {
                try {
                    // 开启事务
                    TransactionManager.StartTransaction();
                    String category_id = "-666";
                    // 检查商品种类是否存在
                    ProdCategory category = prodDao.findProdCategoryByCategoryName(prod
                            .getProdCategory().getName());
                    if (category == null) {
                        // 商品种类不存在--则先添加商品种类,然后添加商品
                        category = prodDao
                                .addCategory(prod.getProdCategory().getName());// 返回值的作用是为了后期容易得到商品种类的ID值
                    }
                    // 获取商品种类的ID
                    category_id = category.getId();
                    // 商品种类存在,添加商品
                    prodDao.addProd(prod, category_id);
                    // 提交事务
                    TransactionManager.CommitTransaction();
                    // 关闭连接
                    TransactionManager.realse();
                } catch (Exception e) {
                    e.printStackTrace();
                    // 事务回滚
                    TransactionManager.RollbackTransaction();
                    System.out.println("back");
                    throw new RuntimeException(e);
                }
            }
        
            public List findProdList() {
                return prodDao.findProdList();
            }
        
            public void upDatePunm(int id, int pnum) {
                prodDao.upDatePnum(id, pnum);
            }
        
            public void delProd(int id) {
                try {
                    TransactionManager.StartTransaction();// 开启事务
                    // 根据商品信息id查找对应的产品信息
                    Prod prod = prodDao.findProdById(id);
                    // 获取种类
                    int category_id = prod.getProdCategory_id();
                    // 根据种类获取该种类的剩余产品
                    List list_prod = prodDao.findProdsByCategoryId(category_id);
                    if (list_prod.size() > 1) {
                        // 如果大于1则只删除当前商品即可
                        prodDao.delProdById(id);
                    } else if (list_prod.size() == 1) {
                        // 如果为1的话,则将该商品和该种类都删除(级联删除)
                        prodDao.delProdById(id);
                        prodDao.delCategoryByCategoryId(category_id);
                    }
                    TransactionManager.CommitTransaction();// 提交事务
                } catch (Exception e) {
                    e.printStackTrace();
                    TransactionManager.RollbackTransaction();// 回滚事务
                    throw new RuntimeException(e);
                } finally {
                    // 释放资源
                    TransactionManager.realse();
                }
            }
        }
        
    • dao

      • ProdDao

        package com.easymall.dao;
        
        import java.util.List;
        
        import com.easymall.domain.Prod;
        import com.easymall.domain.ProdCategory;
        
        public interface ProdDao {
        
            /**
             * 通过商品种类名称查询数据库是否有此种类
             * 
             * @param string
             * @return 找到了? 商品种类的对象:null;
             */
            ProdCategory findProdCategoryByCategoryName(String string);
        
            /**
             * 添加一个商品种类
             * 
             * @param category
             * @return 添加成功对应的商品种类
             */
            ProdCategory addCategory(String category_name);
        
            /**
             * 添加商品
             * 
             * @param prod
             *            商品
             * @param category_id
             *            商品种类的ID
             * @return void
             */
        
            void addProd(Prod prod, String category_id);
        
            /**
             * 查询所有商品
             * 
             * @return 商品列表
             */
            List findProdList();
        
            /**
             * 通过id更新产品的pnum数据
             * 
             * @param id
             * @param pnum
             */
            void upDatePnum(int id, int pnum);
        
            /**
             * 通过产品id查找对应的商品
             * 
             * @param id
             * @return 商品信息
             */
            Prod findProdById(int id);
        
            /**
             * 通过中了的id查找对应的所有商品
             * 
             * @param category_id
             * @return 该种类对应的所有商品 ---list
             */
            List findProdsByCategoryId(int category_id);
        
            /**
             * 通过商品的id删除商品
             * 
             * @param id
             */
            void delProdById(int id);
        
            /**
             * 通过商品种类的id删除改种类
             * 
             * @param category_id
             */
            void delCategoryByCategoryId(int category_id);
        
        }
        
      • ProdDaoImpl

        package com.easymall.dao;
        
        import java.sql.Connection;
        import java.sql.PreparedStatement;
        import java.sql.ResultSet;
        import java.util.ArrayList;
        import java.util.List;
        
        import com.easymall.domain.Prod;
        import com.easymall.domain.ProdCategory;
        import com.easymall.utils.MySqlUtils;
        import com.easymall.utils.TransactionManager;
        
        public class ProdDaoImpl implements ProdDao {
            Connection conn = null;
            PreparedStatement stat = null;
            ResultSet rs = null;
        
            public ProdCategory findProdCategoryByCategoryName(String name) {
                try {
                    ProdCategory pc = null;
                    conn = TransactionManager.getConn();
                    stat = conn
                            .prepareStatement("select * from prod_category where name=?");
                    stat.setString(1, name);
                    rs = stat.executeQuery();
                    while (rs.next()) {// 一个对象这里才对----------嘻嘻
                        pc = new ProdCategory();
                        pc.setId(rs.getString("id"));
                        pc.setName(rs.getString("name"));
                    }
                    return pc;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
            }
        
            public ProdCategory addCategory(String category_name) {
        
                try {
                    conn = TransactionManager.getConn();
                    conn.setAutoCommit(false);// 设置不自动提交
                    stat = conn
                            .prepareStatement("insert into prod_category(name) values(?)");
                    stat.setString(1, category_name);
                    stat.executeUpdate();
                    // 通过得到刚存入的数据得到相应的id来返回ProdCategory对象
                    ProdCategory pc = null;
                    stat = conn
                            .prepareStatement("select * from prod_category where name=? ");
                    stat.setString(1, category_name);
                    rs = stat.executeQuery();
                    while (rs.next()) {
                        pc = new ProdCategory();
                        pc.setId(rs.getString("id"));
                        pc.setName(rs.getString("name"));
                    }
                    return pc;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
        
                    MySqlUtils.close(null, stat, rs);
                }
        
            }
        
            public void addProd(Prod prod, String category_id) {
        
                try {
                    conn = TransactionManager.getConn();
                    stat = conn
                            .prepareStatement("insert into prod(name,price,pnum,img_url,description,prodCategory_id) values(?,?,?,?,?,?)");
                    stat.setString(1, prod.getName());
                    stat.setDouble(2, prod.getPrice());
                    stat.setInt(3, prod.getPnum());
                    stat.setString(4, prod.getImgurl());
                    stat.setString(5, prod.getDescription());
                    stat.setInt(6, Integer.parseInt(category_id));
        
                    stat.executeUpdate();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
        
            }
        
            public List findProdList() {
                List prod_list = new ArrayList();
                try {
                    // 查询数据库,并把每一条记录包装成Prod对象存入prod_list列表中
                    conn = MySqlUtils.getConn();
                    stat = conn
                            .prepareStatement("select * from prod inner join prod_category where prod.prodCategory_id=prod_category.id");
                    rs = stat.executeQuery();
                    while (rs.next()) {
                        Prod prod = new Prod();
                        prod.setId(rs.getInt(1));
                        prod.setName(rs.getString(2));
                        prod.setPnum(rs.getInt(4));
                        prod.setDescription(rs.getString(7));
                        prod.setImgurl(rs.getString(5));
                        prod.setPrice(rs.getDouble(3));
                        prod.setProdCategory_id(rs.getInt(6));
                        prod.setProdCategory(new ProdCategory(rs.getString(8), rs
                                .getString(9)));
                        prod_list.add(prod);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(conn, stat, rs);
                }
                return prod_list;
            }
        
            public void upDatePnum(int id, int pnum) {
                try {
                    // 通过id更新产品的pnum
                    conn = MySqlUtils.getConn();
                    stat = conn.prepareStatement("update prod set pnum=? where id=? ");
                    stat.setInt(1, pnum);
                    stat.setInt(2, id);
                    stat.executeUpdate();
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        
            public Prod findProdById(int id) {
                try {
                    Prod prod = null;
                    conn = TransactionManager.getConn();
                    stat = conn
                            .prepareStatement("select * from prod inner join prod_category where prod.prodCategory_id=prod_category.id and prod.id=?");
                    stat.setInt(1, id);
                    rs = stat.executeQuery();
                    while (rs.next()) {
                        prod = new Prod();
                        prod.setId(rs.getInt(1));
                        prod.setName(rs.getString(2));
                        prod.setPnum(rs.getInt(4));
                        prod.setDescription(rs.getString(7));
                        prod.setImgurl(rs.getString(5));
                        prod.setPrice(rs.getDouble(3));
                        prod.setProdCategory_id(rs.getInt(6));
                        prod.setProdCategory(new ProdCategory(rs.getString(8), rs
                                .getString(9)));
                    }
                    return prod;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
        
            }
        
            public List findProdsByCategoryId(int category_id) {
        
                List prod_list = new ArrayList();
                try {
                    // 查询数据库,并把每一条记录包装成Prod对象存入prod_list列表中
                    conn = MySqlUtils.getConn();
                    stat = conn
                            .prepareStatement("select * from prod inner join prod_category where prod.prodCategory_id=prod_category.id and prod_category.id=? for update");// 悲观锁解决更新丢失
                    stat.setInt(1, category_id);
                    rs = stat.executeQuery();
                    while (rs.next()) {
                        Prod prod = new Prod();
                        prod.setId(rs.getInt(1));
                        prod.setName(rs.getString(2));
                        prod.setPnum(rs.getInt(4));
                        prod.setDescription(rs.getString(7));
                        prod.setImgurl(rs.getString(5));
                        prod.setPrice(rs.getDouble(3));
                        prod.setProdCategory_id(rs.getInt(6));
                        prod.setProdCategory(new ProdCategory(rs.getString(8), rs
                                .getString(9)));
                        prod_list.add(prod);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
                return prod_list;
        
            }
        
            public void delProdById(int id) {
                try {
                    conn = TransactionManager.getConn();
                    stat = conn.prepareStatement("delete from prod  where id=?");
                    stat.setInt(1, id);
                    stat.executeUpdate();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
        
            }
        
            public void delCategoryByCategoryId(int category_id) {
        
                try {
                    conn = TransactionManager.getConn();
                    stat = conn
                            .prepareStatement("delete  from prod_category  where id=?");
                    stat.setInt(1, category_id);
                    stat.executeUpdate();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    MySqlUtils.close(null, stat, rs);
                }
        
            }
        }
        

再次谈谈缺点

  • 异常的处理【各个地方】
  • 页面的数据判别处理【特指商品添加模块】

你可能感兴趣的:(达内实训,大数据学习痕迹)