继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JSP+Servlet培训班作业管理系统[17] -使用事务完成新增作业功能

程序员大阳
关注TA
已关注
手记 357
粉丝 1.5万
获赞 1523

step1是新增作业的页面workUpdata.jsp,代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用c:标签需要添加本行代码 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>  
    <title>workUpdate.jsp</title>
    <link href="css/content.css" type="text/css" rel="stylesheet"/>
    <link href="css/table.css" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <form action="/HomeworkSystem/ActionServlet?method=save&entityType=Work" method="post">
        <div id="content_top">
            作业信息更新
        </div><!-- user_top end -->
        <div id="content_mid">
            <table class="table_theme1">
                <tr>
                    <td>所属课程:</td>
                    <td>
                        <select name="workCourse">
                            <c:forEach items="${courses}" var="item">
                                <option value="${item.courseId}">${item.courseName}</option>
                            </c:forEach>    
                        </select>
                    </td>
                    <td>作业题目:</td>
                    <td>
                        <input type="text" name="workTitle" value="${work.workTitle}"/>
                    </td>
                </tr>
            </table>
        </div><!-- user_mid end -->
        <div id="content_bottom">
            <input type="submit" value="保存"></input>
        </div><!-- "user_bottom" end -->
      </form>
  </body>
</html>

需要注意以下几点:

1,所属课程的<select>里面加载的课程列表,是往workUpdate.jsp页面跳转时,就携带过来的。至于如何携带的?放在ActionContext的outputParams里面不就Ok了。
2,当点击保存按钮后,表单(包含新增作业所属课程信息及作业题目信息)被提交给/HomeworkSystem/ActionServlet?method=save&entityType=Work

step2,ActionServlet只承担接受参数、返回参数的功能,具体流转交给ActionController,ActionController对method=save&entityType=Work的解析如下:

else if(context.getOperationType().equals("save")){
            //注意,点击保存后,不同的实体需要携带不同的参数列表,所以采用createEntityFromRequest来创建实体
            Object entity=EntityFactory.createEntityFromRequest(context.getEntityType(), request);
            Map<String,Object> map=new HashMap<String,Object>();
            context.setInputParams(map);
            //只要是保存操作,就需要待保存的实体
            map.put("waitSaveEntity", entity);
            //需要根据entityId判断是新增还是修改
            String id=request.getParameter("entityId");
            if(id==null||"".equals(id)){
                context.setEntityId(-1);
            }else{
                context.setEntityId(Integer.parseInt(id));
            }
            //因为Save之后要跳到列表,有些列表需要根据登录用户身份显示,所以
            map.put("sessionUser", request.getSession().getAttribute("sessionUser"));
            //------------------------------------------------------------------save work 
            //注意因为work是跟课程相关的,修改work后要跳转到当前课程所有作业列表,所以添加该输入项
            if(context.getEntityType().equals("Work")){
                map.put("courseId", request.getParameter("workCourse"));
            }

需要携带的参数已经在注释里面描述的很清楚了。

step3随后,ActionController将参数传给SaveWorkAction

else if(context.getOperationType().equals("save")){
            //------------------------------------------------------------------save work 需要事务
            if(context.getEntityType().equals("Work")){
                return new SaveWorkAction(context);
            }
            return new SaveAction(context);
        }

step4,前面实际上都是些跳转及跳转时候需要携带的参数信息,SaveWorkAction是具体的逻辑实现如下:

package action;
import inter.IOperation;

import java.util.ArrayList;
import java.util.Date;

import database.MySQLHandler;
import operation.LessonOperation;
import operation.WorkOperation;
import servlet.ActionController;
import action.support.Action;
import action.support.ActionContext;
import entity.Lesson;
import entity.Work;
import exception.MyException;
import factory.OperationFactory;
/***
 * 动作:保存作业(注意作业无法修改,都是新增,而且新增时需要事务)
 * @author 猫哥
 * @date 2017.2.17
 */
public class SaveWorkAction extends Action{
    public SaveWorkAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        //获取最大work_id,加一为新id
        WorkOperation workOper=(WorkOperation)OperationFactory.createOperation("Work");
        int maxId=workOper.selectMaxId();
        //肯定是新增,获取新增的work信息,maxId+1是没问题的,如果正好别人插入maxId+1,大不了就失败了
        Work one=(Work)context.getInputParams().get("waitSaveEntity");
        one.setWorkId(maxId+1);
        //待执行的sql列表
        ArrayList<String> sqlList=new ArrayList<String>();
        //第一条语句system_Work中新增作业
        sqlList.add("insert into system_Work(work_id,Work_title,work_time,work_course)"
                +" values('"+one.getWorkId()+"','"+one.getWorkTitle()+"','"+one.getWorkTime()+"','"+one.getWorkCourse().getCourseId()+"')");
        //第二条语句student_job中添加多条
        LessonOperation lessonOper=(LessonOperation)OperationFactory.createOperation("Lesson");
        ArrayList<Lesson> lessonList=(ArrayList<Lesson>)lessonOper.selectByCourseId(one.getWorkCourse().getCourseId());
        StringBuilder sqlLesson=new StringBuilder();
        sqlLesson.append("insert into student_Job(Job_score,job_user,job_work) values");
        for(Lesson lesson:lessonList){
            String sql="('-2','"+lesson.getLessonUser().getUserId()+"','"+one.getWorkId()+"'),";
            sqlLesson.append(sql);
        }
        sqlLesson.deleteCharAt(sqlLesson.length()-1);
        if(lessonList.size()>0)
            sqlList.add(sqlLesson.toString());
        //执行事务
        MySQLHandler hand=new MySQLHandler();
        hand.doTransaction(sqlList);
        //新增完毕后跳转查看作业页面
        context.setOperationType("view");
        Action action=ActionController.dispatchAction(context);
        return action.execute();
    }
}

OK,所有的关键都在hand.doTransaction(sqlList);,这一句将sqlList中所有的sql语句按事务执行,也就是要么都执行成功,要么都完蛋不执行。

step5那么,doTransaction是如何实现的呢,如下

public Boolean doTransaction(ArrayList<String> sqlList) throws MyException{
        try{
            if(conn==null)//未分配
                conn=MySQLPool.getConnecton();//用时从池中取,很爽快
            //开始事务(不让mysql自动提交了,程序员做主何时一起提交或者还是回退)
            conn.setAutoCommit(false);
            for(String sql:sqlList){
                stmt=conn.createStatement();
                stmt.executeUpdate(sql);
            }
            //此处提交事务,如果中间所有执行语句没错,则全部一起执行,如果有错跳到catch
            conn.commit();
            return true;
        }
        catch (Exception ex) {
            try {
                //如果有错误,则回归到所有sql未执行状态
                conn.rollback();
            } catch (SQLException sqlEx) {
                new MyException(new Date(),sqlEx.getMessage(),"事务回滚错误");
            }  
            throw new MyException(new Date(),ex.getMessage(),"数据库执行错误");
        }finally{
            MySQLPool.release(conn);//用完归还
        }
    }

OK,到此结束,因为事务的原理上一篇讲过,此处给出实现即可。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP