大数据正式24

大数据正式24

数据库中的锁机制

  • 共享锁
    • 共享锁和共享锁可以共存
    • 共享锁和排他锁不可以共存
    • 非Serializable级别的任何查询都不加锁,在Serializable级别的查询加锁
  • 排它锁
    • 排它锁和任何锁都不可以共存
    • 任意隔离级别的增删改都加
  • 数据库中的锁的设计
    • 两个查询:没必要加锁
    • 两个增删改:必须互斥
    • 一个查询,一个修改:Serializable级别的需要加锁,其他级别的不需要加锁

具体分析【锁对象--操作--是否可以共同操作】

操作对象【对象一:对象二】 对象一操作 对象二操作 分析 结果
【非Serializable:非Serializable】 【不加锁:不加锁】 可以共同操作
【非Serializable:Serializable】 【不加锁:共享锁】 可以共同操作
【Serializable:Serializable】 【共享锁:共享锁】 可以共同操作
【非Serializable:非Serializable】 增删改 【不加锁:排它锁】 可以共同操作
【Serializable:非Serializable】 增删改 【共享锁:排它锁】 不可以共同操作
【非Serializable:Serializable】 增删改 【不加锁:排它锁】 可以共同操作
【Serializable:Serializable】 增删改 【共享锁:排它锁】 不可以共同操作
【非Serializable:非Serializable】 增删改 增删改 【排它锁:排它锁】 不可以共同操作
【Serializable:非Serializable】 增删改 增删改 【排它锁:排它锁】 不可以共同操作
【非Serializable:Serializable】 增删改 增删改 【排它锁:排它锁】 不可以共同操作
【Serializable:Serializable】 增删改 增删改 【排它锁:排它锁】 不可以共同操作

其他锁

  • 死锁:如果有两个以上的资源,互相等待
    • 例:当看客户端都是Serializable隔离级别时,两边先查询【共享锁】,再修改【想升级为排它锁】,都无法执行---资源互等,产生死锁
    • 解决
      1. 避免死锁
      2. 解决死锁【数据库没有避免死锁,只能是遇到错的时候,关闭错误的请求,进行正确的操作】

EasyMall中的事务控制

  • 遇到的问题:Service层控制事务需要用到同一个Connection,而Connection是Dao层的特有对象,那该怎么办呢?
  • 图解问题:
  • 解决:解决耦合--》管理事务--》专门的事务管理【将耦合统一管理,方便未来开发和维护】
    • Connection管理
      • 如果所有的用到的都使用同一个Static的Connection,则会出现多线程不安全的问题
        • 方案一:类内部加锁--效率太低
        • 方案二:ThreadLocal,线程流的传递同时将数据也进行传递
  • ThreadLocal

    • 本地线程变量
    • 本质:利用程序的执行机制,在上游存放数据,下游利用该数据
    • 图解:
    • 方法
    • 例子

      package com.easymall.utils;
      
      public class T {
          static ThreadLocal tl = new ThreadLocal();
      
          public static void main(String[] args) {
              tl.set("abc");
              a();
          }
      
          public static void a() {
              b();
          }
      
          public static void b() {
              c();
          }
      
          public static void c() {
              System.out.println(tl.get());
          }
      }
      
      • 执行结果

        abc
        
    • EasyMall中添加产品模块

      • 流程
      • ProdService

        • ProdServiceImpl

          package com.easymall.service;
          
          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);
                  }
              }
          }
          
      • ProdDao

        • ProdDaoImpl

          package com.easymall.dao;
          
          import java.sql.Connection;
          import java.sql.PreparedStatement;
          import java.sql.ResultSet;
          
          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);
                  }
          
              }
          }
          
      • utils

        • TransactionManager

          package com.easymall.utils;
          
          import java.sql.Connection;
          import java.sql.SQLException;
          
          /**
           * 注意:使用了ThreadLocal类-------通过线程的【传递性】来传递【互不影响】的数据
           * 
           * @author Administrator
           * 
           */
          
          public class TransactionManager {
              private static ThreadLocal tl = new ThreadLocal();
          
              // 构造函数私有化
              private TransactionManager() {
                  super();
              }
          
              // 开启事务
              public static void StartTransaction() {
                  // 创建连接
                  Connection conn = MySqlUtils.getConn();
                  tl.set(conn);
                  // 开启事务
                  try {
                      if (null != tl.get()) {
                          tl.get().setAutoCommit(false);
          
                      }
                  } catch (SQLException e) {
                      e.printStackTrace();
                      throw new RuntimeException(e);
                  }
              }
          
              // 提交事务
              public static void CommitTransaction() {
                  if (null != tl.get()) {
                      try {
                          tl.get().commit();
                      } catch (SQLException e) {
                          e.printStackTrace();
                          throw new RuntimeException(e);
                      }
                  }
              }
          
              // 回滚事务
              public static void RollbackTransaction() {
                  if (null != tl.get()) {
                      try {
                          tl.get().rollback();
                      } catch (SQLException e) {
                          e.printStackTrace();
                          throw new RuntimeException(e);
                      }
                  }
              }
          
              // 获取Conn
              public static Connection getConn() {
                  return tl.get();
              }
          
              // 释放连接
              public static void realse() {
                  Connection conn = tl.get();
                  MySqlUtils.close(conn, null, null);
                  tl.remove();
              }
          }
          

Easymall商品模块展示

  • 流程
    1. index.jsp中点击“所有商品”
    2. ProdListServlet调用Service查询所有商品信息,存入Request域,带到页面展示
    3. ProdDao查询所有商品
  • 相关技术
    • 数据库查询
      • 笛卡尔查询
        • select * from t1,t2;
      • 内连接查询
        • 在笛卡尔积的基础上选
        • select * from t1,t2 where ti.id = td.t1_id;
        • select * from t1 inner join t2 on t1.id = t2.t1_id;
      • 外链接查询
        • 在内连接的基础上增加左表剩下的数据
        • 左外连接查询
          • select * from t1 left join t2 on t1.id = t2.t1_id;
        • 右外连接查询
          • select * from t1 right join t2 on t1.id = t2.t1_id;
        • 全外连接
          • select * from t1 full join t2 on t1.id = t2.t1_id;//mysql中没有实现
          • select * from t1 left join t2 on t1.id = t2.t1_id union select * from t1 right join t2 on t1.id = t2.t1_id;
  • 商品列表(前台)

    • 效果展示
    • 代码

      • 展示页面

        <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"
            buffer="0kb"%>
        <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
        <%
            String path = request.getContextPath();
            String basePath = request.getScheme() + "://"
                    + request.getServerName() + ":" + request.getServerPort()
                    + path + "/";
        %>
        
        
        
        
        
        
        
        
            <%@include file="head.jsp"%>
            
        商品名: 商品种类: 商品价格区间: -
        ${prod.name}
        ${prod.price}
        133人评价
        <%@include file="foot.jsp"%>
      • web层

        • ProdImgServlet(获取二进制图片)

          package com.easymall.web;
          
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;
          
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          
          public class ProdImgServlet extends HttpServlet {
          
              public void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  // 获取产品图片地址
                  String imgurl = request.getParameter("imgurl");
                  // 将图片的二进制发往页面
                  // 读取并写入输出
                  File file = new File(this.getServletContext().getRealPath(imgurl));
                  InputStream in = new FileInputStream(file);
                  OutputStream os = response.getOutputStream();
                  int len = -1;
                  byte[] data = new byte[1024];
                  while ((len = in.read(data)) != -1) {
                      os.write(data, 0, len);
                  }
              }
          
              public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
          
              }
          
          }
          
        • ProdListServlet

          package com.easymall.web;
          
          import java.io.IOException;
          import java.util.List;
          
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          
          import com.easymall.domain.Prod;
          import com.easymall.factory.BasicFactory;
          import com.easymall.service.ProdService;
          
          @SuppressWarnings("serial")
          public class ProdListServlet extends HttpServlet {
          
              public void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  // 调用Service查询所有商品
                  ProdService service = BasicFactory.getFactory().getObj(
                          ProdService.class);
                  List list = service.findProdList();
                  // 将数据放入Request域
                  request.setAttribute("prod_lists", list);
                  // 转发到prodList.jsp页面
                  request.getRequestDispatcher("prodList.jsp").forward(request, response);
              }
          
              public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
          
              }
          
          }
          
      • 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);
          }
          
        • 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);
              }
          }
          
      • 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);
          
          }
          
        • ProdDaoImpl

              package com.easymall.dao;
          
              import java.sql.Connection;
              import java.sql.PreparedStatement;
              import java.sql.ResultSet;
              import java.util.ArrayList;
              import java.util.Collections;
              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);
                      }
                  }
              }
          
  • 商品修改(后台)

    • 效果展示
      • ![] (https://i.imgur.com/1x9wHPB.png)
    • 代码

      • 展示页面

      • web层

        • ManagerProdListServlet

          package com.easymall.web;
          
          import java.io.IOException;
          import java.util.List;
          
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          
          import com.easymall.domain.Prod;
          import com.easymall.factory.BasicFactory;
          import com.easymall.service.ProdService;
          
          @SuppressWarnings("serial")
          public class ManagerProdListServlet extends HttpServlet {
          
              public void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  // 调用Service查询所有商品
                  ProdService service = BasicFactory.getFactory().getObj(
                          ProdService.class);
                  List list = service.findProdList();
                  // 将数据放入Request域
                  request.setAttribute("prod_lists", list);
                  // 转发到prodList.jsp页面
                  request.getRequestDispatcher(
                          request.getContextPath() + "/backend/manageProdList.jsp")
                          .forward(request, response);
              }
          
              public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  this.doGet(request, response);
              }
          
          }
          
        • ManageUpdatePnumServlet(更新pnum)

          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;
          
          public class ManageUpdatePnumServlet 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 {
                  // 获取参数
                  int id = Integer.parseInt(request.getParameter("id"));
                  int pnum = Integer.parseInt(request.getParameter("pnum"));
                  System.out.println(id + "~~" + pnum);
                  // 调用Service来更新数据
                  ProdService service = BasicFactory.getFactory().getObj(
                          ProdService.class);
                  service.upDatePunm(id, pnum);
                  // 直接输出结果----ajax
                  response.getWriter().write(pnum + "");
              }
          }
          
        • ProdImgServlet(获取二进制图片)

          package com.easymall.web;
          
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;
          
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          
          public class ProdImgServlet extends HttpServlet {
          
              public void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  // 获取产品图片地址
                  String imgurl = request.getParameter("imgurl");
                  // 将图片的二进制发往页面
                  // 读取并写入输出
                  File file = new File(this.getServletContext().getRealPath(imgurl));
                  InputStream in = new FileInputStream(file);
                  OutputStream os = response.getOutputStream();
                  int len = -1;
                  byte[] data = new byte[1024];
                  while ((len = in.read(data)) != -1) {
                      os.write(data, 0, len);
                  }
              }
          
              public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
          
              }
          
          }
          
      • service层(见上)

      • dao层(见上)

EasyMall遗留的问题

  1. 注册的JavaScript处理-----逻辑不完善
  2. 异常的具体处理---------很不完善(~ 。~)
  3. 商品添加的JavaScript判断和后台判断处理-----这个记得参考【注册】
  4. 大致大体有这些,具体的细节遇到记得完善。。。

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