spring+hibernate+事务

1 篇文章 0 订阅
0 篇文章 0 订阅

数据库连接泄漏是件可怕的事情,可能直接导致系统停止响应,另外因事务管理错误而导致数据出现不一致也是件可怕的事情,在后台系统中,这两个问题经常会结伴出现,本文将通过案例详解使用Spring+Hibernate时可能导致问题的几种情况,希望对大家有所帮助。

文章比较长,如果你是遇到了问题正急求解决方案的话,可以先只读这一条:检查你的dao是否有直接使用session,修改为使用hibernateTemplate。
如果你希望更多的了解session, hibernateTemplate, transaction,请继续。

以下案例基于Struts2.3.1+Spring3.1.1+hibernate3.5.4完成,案例场景为对系统参数进行管理,涉及如下四个类:
Action PropertyAction
Service PropertyService/PropertyServiceImpl
DAO PropertyDAO(继承HibernateDaoSupport)
Entity SysProperty
1. Action中直接调用dao,未使用getHibernateTemplate
在一个复杂的多层架构系统中,事务控制在service中完成是更合理的,不应交由view层来控制,本文假定你是这么做的。一般我们代码的处理顺序为action->service->dao,然而总会有人会打破这种逻辑,打破可以,但要注意如下问题。
假定Action中有如下代码:
1 @Autowired
2 private PropertyDAO propertyDAO;
3 @Override
4 public String execute() throws Exception {
5      model = propertyDAO.get(1L);
6      return null;
7 }

这里action直接访问了dao中的get方法,因事务配置在service层,因此这里是没有事务控制的。
接下来我们看dao中的get方法,假定你的定义如下:
1 public SysProperty get(Long id) {
2     return (SysProperty) getSession().get(SysProperty.class, id);
3 }

代码很简单,getSession是父类HibernateDaoSupport中提供的方法,这里直接通过实体Id get得到结果。
接下来发布一下系统,访问页面,好像一切OK,但是,再刷新几下看看,可能你的连接池配置的比较大,要刷新多次,最后你发会现你的系统停止了响应。更直接点,调用你采用的连接池中的相关API检测下当前连接占用情况,你会发现刷新一次,被占用连接增加一个,可怕的事情发生了。
小结:在无事务管理器控制的情况下,通过getSession()打开的session不会被关闭,这个session所占用的数据库连接也不会被释放。

接下来,来点更可怕的,假设你的action中是这样的:
1 private List<Long> ids;
2 @Override
3 public String execute() throws Exception {
4   for(Long id: ids) {
5     results.add(propertyDAO.get(id));
6   }
7   return null;
8 }
9
这时尝试一次传入多个id进行请求,请求结束后检查下连接数,你发现传入多少ID,就有多少连接被占用,也就是说每一次对dao的get调用都会占用一个不可释放的连接。
小结:如果没有配置事务管理器且直接使用getSession得到session,每次getSession都会创建一个新的session,每个session占用一个新的数据库连接,session无线程级别的共享。

2. Action中直接调用dao,使用getHibernateTemplate
当然,你可能没遇到过前面的情况,因为你会在DAO中这样写代码:
1 public SysProperty get(Long id) {
2     return getHibernateTemplate().get(getEntityClass(), id);
3 }
那么是否就一切OK呢?如果只是想解决连接泄漏这个问题的话,答案是Yes,尝试多次请求,检查下你的连接池状况,没有连接泄漏的情况出现。所以简单而可靠的办法就是不再直接使用getSession,而是使用getHibernateTemplate进行相应操作,当需要使用session时,可以用下面的方法:
getHibernateTemplate().execute(new HibernateCallback<T>() {
  public T doInHibernate(Session session) throws HibernateException {
    Query queryObject = session.createQuery(hql);
    //....
  }
});
But...如果你的系统真的出现了连接泄漏,可能你需要关注更多。
还是前面Action中根据ID循环查询的操作,在这个案例中,每一次Dao的get方法都将重复这样的逻辑:创建session,分配session一个连接,关闭session,释放session占用的连接,也就是说session不会在线程级别共享。让我们继续,进入第三种情况来进一步说明。

3. Service未合理配置事务管理器
绝大部分情况下我们会给service配置事务管理器,可能是通过xml或是@Transactional注解,但并非配置了就OK了。看下面的例子:
@Transactional
public class PropertyServiceImpl implements PropertyService {
    @Autowired
    private PropertyDAO propertyDAO;
  
    @PostConstruct
    public void init(){
        propertyDAO.get(1L);
    }
    //
}
当然,假定你的DAO还是写成了这样:
public SysProperty get(Long id) {
    return (SysProperty) getSession().get(SysProperty.class, id);
}
你期望在service初始化好后做一些数据库操作,你也给service配置了事务管理器,接下来你启动应用,然后检查连接池中的连接数,你会发现有连接未被释放!可能你会果断的修改dao中的方法:
public SysProperty get(Long id) {
    return getHibernateTemplate().get(getEntityClass(), id);
}
然后你会理所当然的认为,即使配置了事务管理器,依然不能使用getSession(),事实可能并非如此。
我们调整一下代码,不在init中调用dao中的get方法,改为如下:
public SysProperty getProperty(Long id) {
    return propertyDAO.get(id);
}
然后DAO继续使用(SysProperty) getSession().get(SysProperty.class, id),而action中的调用修改为:
@Autowired
private PropertyService propertyService;
@Override
public String execute() throws Exception {
    model = propertyService.getProperty(1L);
    return null;
}
重新发布,调用,检查连接数,发现无被占用连接存在。
小结:如果正确配置了事务管理器,getSession是安全的。

这时要清楚spring是通过AOP来实现事务控制的,而@PostConstruct方法不会受AOP控制,因此上面的init方法等于无事务管理器。
那么再回头来说,是否只要dao中使用getHibernateTemplate就不会有问题呢?
假定service中的@PostConstruct方法如下:
@PostConstruct
public void init(){
    SysProperty p = new SysProperty();
    p.setName("test_property_1");
    propertyDAO.save(p);
}
强调一下,前面已经提到这个方法不受spring的事务管理器控制。
假定DAO中的save方法如下:
public void save(SysProperty o){
    getSession().save(o);
}
启动一下应用,检查一下连接数,再检查一下数据是否有存储到数据库中。因为我们直接使用了getSession,因此连接不会释放,这点前面已经提到,但同时我们还将发现数据没有被存储,当然这个也好理解,因为上面已经提到这个方法未配置事务管理器。
小结:通过getSession().save()保存数据时,事务不会自动提交。

现在再修改下DAO中的save方法:
public void save(SysProperty o){
    getHibernateTemplate().save(o);
}
启动一下应用,检查一下连接数,再检查一下数据是否有存储到数据库中。因为我们使用hibernateTemplate,因此连接有释放,这点前面已经提到,但同时我们还发现数据也已存储到数据库中,说明hibernateTemplate会自动提交事务。
小结:如果未配置事务管理器,通过hibernateTemplate操作时,会自动创建并提交事务。

所以如果你觉得使用hibernateTemplate就OK了,那就要小心下面的代码了:
@PostConstruct
public void init(){
  //1. 从你的账号A中扣除一万块
  //2. 这里的代码抛出了异常
  //3. 将你的账号B中增加一万块
}
如果上面的第2步出现了异常,那么因为1的事务已经提交,而3却没有执行,最终导致了数据的不一致,后果和连接泄漏一样严重!
除了@PostConstruct,还有其它原因会导致@Transactional无效,假定我们的service配置了事务管理器,但存在如下代码:
pubic void someServiceMethod(){
  new Thread(){
    public void run(){
        doSomethingLater();
    }
  }
}

public void doSomethingLater(){
  //做一系列数据库操作
}
那么你可以去验证下doSomethingLater是否受事务管理器控制,事实上并不会,所以你需要理解spring AOP的机制,否则一个小坑会酿成灾难。
这里还有一种情况,你不是在类上面配置@Transactional,而是在方法上面配置,假定存在如下的代码:
//该方法不需要事务控制
public void method1(){
    method2();
}

//下面的方法需要事务控制
@Transactional
public void method2(){
    //do something
}
因为你需要给不同的方法配置不同的事务机制,因此你没有在类上面进行配置,然后你在客户端进行了如下调用:service.method1(); method2中的方法会受事务管理吗?可悲的是并不会。
上面讲到的线程调用和内部方法调用可以这样来处理:
@Autowired
private ApplicationContext context; 
public void method1(){
    PropertyService service = context.getBean(PropertyService.class);
    service.method2();
}
小结:注意spring的AOP机制

4. Service合理配置事务管理器
最后补充一下,如果事务管理器配置正确的话会发生什么。这时不管你是用getSession还是getHibernateTemplate,结果都是一样,session将在thread级别共享,session只有一个。

总结:难得这周开始工作变得清闲,上班时间还能写写博客,想想前段日子真是自己何苦为难自己。回到话题,使用getSession没什么大错,因为你本应正确配置事务管理器。使用hibernateTemplate能解决所有连接泄漏的问题,但要小心他可能隐藏的事务问题。另外就是spring中内部方法调用时AOP的问题,创建新线程时的事务问题。最后希望这篇有点绕的文章能给你带来帮助。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一共四个,其中pdf 三个包,源码一个包 第一章 J2EE快速入门 1.1 J2EE概述 1.1.1 J2EE的来源 1.1.2 J2EE整体框架 1.1.3 从J2EE到JavaEE 1.2 J2EE组件 1.2.1 客户端组件 1.2.2 Web组件 1.2.3 业务逻辑组件 1.3 J2EE容器 1.3.1 容器服务 1.3.2 容器类型 1.4 J2EE核心技术 1.4.1 Servlet 1.4.2 JSP(Java服务页面) 1.4.3 EJB(企业JavaBean) 1.4.4 JDBC(Java数据库连接) 1.4.5 JTA/JTS(Java事务) 1.4.6 JNDI(Java命名和目录服务) 1.4.7 JavaMail(Java邮件服务) 1.4.8 RMI(远程方法调用) 1.4.9 JMS(Java消息服务) 1.4.10 JMX(Java分布式管理) 1.4.11 JACC(Java容器授权合同) 1.4.12 JCA(Java连接器体系) 1.5 小结 第二章 MVC模式介绍 2.1 MVC模式概述 2.1.1 MVC模式的设计思想 2.1.2 MVC模式的处理过程 2.2 Model规范 2.2.1 Model1规范 2.2.2 Model2规范 2.3 使用MVC的优劣 2.3.1 使用MVC模式的好处 2.3.2 使用MVC模式的不足之处 2.4 目前市场上常见的轻量级J2EE开发容器 2.5 小结 第二篇 建立和使用J2EE的开发平台 第三章 建立Java的开发平台 3.1 建立Java的开发环境 3.1.1 下载JDK 3.1.2 安装JDK 3.1.3 设定Path、Classpath和JAVA_HOME 3.2 验证JDK是否安装成功 3.3 建立J2EE的开发环境 3.3.1 下载SDK 3.3.2 安装SDK 3.3.3 设定Path、Classpath和J2EE_HOME 3.4 小结 第四章 Tomcat使用指南 4.1 Tomcat简介 4.1.1 Tomcat的目录结构 4.1.2 Tomcat的配置参数 4.2 建立Tomcat的开发环境 4.2.1 下载Tomcat 4.2.2 设定TOMCAT_HOME 4.3 验证Tomcat是否安装成功 4.4 创建和发布Web应用 4.4.1 创建和发布JSP应用程序 4.4.2 创建和发布Servlet应用程序 4.5 小结 第五章 Eclipse使用指南 5.1 Eclipse简介 5.1.1 Eclipse的历史 5.1.2 Eclipse的运行机制 5.2 建立Eclipse的开发环境 5.2.1 下载Eclipse 5.2.2 配置Eclipse 5.3 整合Eclipse和Tomcat 5.3.1 下载Eclipse的Tomcat插件 5.3.2 为Eclipse配置Tomcat插件 5.4 使用Eclipse建立Web开发项目 5.5 Eclipse的常用快捷键 5.5.1 有关格式化的快捷键 5.5.2 有关调试的快捷键 5.5.3 有关重构的快捷键 5.6 小结 第六章 Log4j使用指南 6.1 Log4j介绍 6.1.1 Log4j历史 6.1.2 Log4j组成 6.2 建立Log4j的开发环境 6.2.1 下载Log4j 6.2.2 配置Log4j 6.3 Log4j的使用方法 6.3.1 配置Log4j 6.3.2 配置根Logger 6.3.3 指定日志输出位置 6.3.4 指定日志输出格式 6.3.5 指定日志输出优先级 6.3.6 在代码中使用Log4j 6.4 改进Log4j 6.5 小结 第七章 Ant使用指南 7.1 Ant介绍 7.1.1 Ant简介 7.1.2 为什么要使用Ant 7.2 建立Ant的开发环境 7.2.1 下载Ant 7.2.2 配置Ant 7.3 Ant的使用方法 7.3.1 Ant能完成的工作 7.3.2 配置文件build.xml 7.3.3 编译源代码 7.3.4 创建JAR文件 7.4 小结 第八章 JUnit使用指南 8.1 JUnit介绍 8.1.1 JUnit简介 8.1.2 为什么要使用JUnit 8.2 建立JUnit的开发环境 8.2.1 下载JUnit 8.2.2 配置JUnit 8.3 JUnit的使用方法 8.3.1 继承TestCase 8.3.2 编写测试方法 8.3.3 编写断言 8.4 JUnit的新特性 8.4.1 改变测试方法的命名方式 8.4.2 不再继承TestCase 8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 9.3.1 添加CVS资源库 9.3.2 提交和更新代码 9.4 小结 第三篇 J2EE开发工具整合技术 第十章 使用Spring快速实现Web开发 10.1 Spring介绍 10.1.1 Spring简介 10.1.2 下载Spring 10.1.3 配置Spring 10.2 Spring核心思想 10.2.1 反向控制(IoC) 10.2.2 依赖注入(DI) 10.3 利用Spring在JSP页面输出“HelloWorld”的示例 10.3.1 建立myHelloWorld工程 10.3.2 编写JSP页面helloWorld.jsp 10.3.3 编写控制器HelloWorldController.java 10.3.4 建立Spring的配置文档dispatcherServlet-servlet.xml 10.3.5 配置web.xml 10.3.6 启动Tomcat运行程序 10.4 Spring 的视图(View) 10.4.1 视图简介 10.4.2 视图解析 10.5 Spring的控制器(Controller) 10.5.1 Controller接口 10.5.2 命令控制器(BaseCommandController) 10.5.3 表单控制器(SimpleFormController) 10.5.4 多动作控制器(MultiActionController) 10.6 Spring的视图映射机制 10.6.1 分发器(DispatcherServlet) 10.6.2 视图映射 10.7 Spring的模型(Model) 10.7.1 模型简介 10.7.2 模型封装 10.8 小结 第十一章 使用Struts快速实现Web开发 11.1 Struts介绍 11.1.1 Struts简介 11.1.2 Struts和Spring比较 11.1.3 下载Struts 11.1.4 配置Struts 11.2 Struts的核心 11.2.1 ActionServlet(分发器) 11.2.2 Action(控制器) 11.2.3 Action Mapping(映射) 11.2.4 ActionForm(表单控制器) 11.2.5 ActionErrors(错误处理) 11.2.6 DispatchAction(多动作控制器) 11.3 利用Struts实现用户登录的示例 11.6.1 编写实现登录的页面login.jsp 11.6.2 编写存储登录用户信息的类User.java 11.6.3 编写控制器LoginAction.java 11.6.4 配置Struts文档struts-config.xml 11.6.5 配置web.xml 11.6.6 启动Tomcat运行示例 11.4 整合Spring和Struts 11.4.1 Spring和Struts的整合方式 11.4.2 编写实现登录的页面regedit.jsp 11.4.3 编写存储登录用户信息的类User.java 11.4.4 编写控制器RegeditAction.java 11.4.5 编写业务逻辑接口Regedit.java 11.4.6 编写具体的业务逻辑类RegeditImpl.java 11.4.7 编写Struts的配置文件struts-config.xml 11.4.8 编写Spring的配置文件spring-config.xml 11.4.9 配置web.xml 11.4.10 启动Tomcat运行示例 11.5 小结 第十二章 使用Hibernate快速实现持久层处理 12.1 Hibernate介绍 12.1.1 Hibernate简介 12.1.2 下载Hibernate 12.1.3 配置Hibernate 12.2 Hibernate的核心 12.2.1 Configuration(配置Connection) 12.2.2 SessionFactory(Connection工厂) 12.2.3 Session(提供Connection) 12.3 使用Hibernate操作数据库的示例 12.3.1 创建数据库表 12.3.2 编写表对应的JavaBean 12.3.3 编写JavaBean对应的Xml 12.3.4 编写Hibernate的配置文件 12.3.5 编写并验证测试程序 12.4 Hibernate的配置文件 12.4.1 Hibernate的两种配置方式 12.4.2 配置数据库连接池 12.4.3 使用JNDI 12.5 使用Hibernate的工具快速生成映射文件和POJO 12.5.1 使用MiddleGen根据数据库产生映射文件 12.5.2 使用hbm2java根据映射文件产生POJO 12.6 整合Struts、SpringHibernate实现用户管理 12.6.1 Struts、SpringHibernate的整合方式 12.6.2 编写用户注册画面regedit.jsp 12.6.3 编写用户登录画面login.jsp 12.6.4 编写注册控制器RegeditAction.java 12.6.5 编写登录控制器LoginAction.java 12.6.6 建立数据库表 12.6.7 生成映射文件User.hbm.xml 12.6.8 生成POJO 12.6.9 编写注册的业务逻辑接口Regedit.java 12.6.10 编写注册的业务逻辑类RegeditImpl.java 12.6.11 编写登录的业务逻辑接口Login.java 12.6.12 编写登录的业务逻辑类LoginImpl.java 12.6.13 编写用户接口UserDAO.java 12.6.14 编写用户实现类UserDAOImpl.java 12.6.15 编写Struts的配置文件struts-config.xml 12.6.16 编写SpringHibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 13.2.2 需求规格说明书 13.3 系统设计 13.3.1 设计视图层 13.3.2 设计持久层 13.3.3 设计业务逻辑层 13.3.4 设计控制层 13.4 架构设计和环境搭配 13.4.1 网上调查系统采用的架构 13.4.2 在Eclipse下建立项目mySurvey 13.4.3 编写本项目的Ant文件 13.4.4 配置本项目的web.xml文件 13.5 编写网上调查系统的JSP页面 13.5.1 用户注册画面regedit.jsp 13.5.2 用户登录画面login.jsp 13.5.3 设定调查题目的画面surveyName.jsp 13.5.4 设定调查项目的画面surveyOption.jsp 13.5.5 设定调查子项目的画面surveyChildOption.jsp 13.5.6 填写调查的画面survey.jsp 13.5.7 查看调查结果的画面surveyOK.jsp 13.6 根据数据库表生成XML和POJO 13.6.1 生成对应的XML 13.6.2 生成POJO 13.7 编写网上调查系统的DAO 13.7.1 用户DAO接口UserDAO.java 13.7.2 调查题目DAO接口SurveyDAO.java 13.7.3 调查项目DAO接口SurveyOptionDAO.java 13.7.4 调查子项目DAO接口SurveyChildDAO.java 13.7.5 调查结果DAO接口SurveyChildCountDAO.java 13.7.6 用户DAO实现类UserDAOImpl.java 13.7.7 调查题目DAO实现类SurveyDAOImpl.java 13.7.8 调查项目DAO实现类SurveyOptionDAOImpl.java 13.7.9 调查子项目DAO实现类SurveyChildDAOImpl.java 13.7.10 调查结果DAO实现类SurveyChildCountDAOImpl.java 13.8 编写网上调查系统的业务逻辑类 13.8.1 注册接口Regedit.java 13.8.2 登录接口Login.java 13.8.3 设定调查题目接口SetSurvey.java 13.8.4 设定调查项目接口SetSurveyOption.java 13.8.5 设定调查子项目接口SetSurveyChild.java 13.8.6 统计调查结果接口SetSurveyChildCount.java 13.8.7 注册实现类RegeditImpl.java 13.8.8 登录实现类LoginImpl.java 13.8.9 设定调查题目实现类SetSurveyImpl.java 13.8.10 设定调查项目实现类SetSurveyOptionImpl.java 13.8.11 设定调查子项目实现类SetSurveyChildImpl.java 13.8.12 统计调查结果实现类SetSurveyChildCountImpl.java 13.9 编写网上调查系统的控制器类 13.9.1 登录控制器类LoginAction.java 13.9.2 注册控制器类RegeditAction.java 13.9.3 设定调查题目控制器类SurveyAction.java 13.9.4 设定调查项目控制器类SetSurveyAction.java 13.10 编写配置文件dispatcherServlet-servlet.xml 13.11 运行验证程序 13.12 小结 第十四章 内容管理系统 14.1 系统概述 14.2 需求分析 14.2.1 系统用例图 14.2.2 需求规格说明书 14.3 系统设计 14.3.1 设计视图层 14.3.2 设计持久层 14.3.3 设计业务逻辑层 14.3.4 设计控制层 14.4 架构设计和环境搭配 14.4.1 内容管理系统采用的架构 14.4.2 在Eclipse下建立项目myEdition 14.4.3 编写本项目的Ant文件 14.4.4 配置本项目的web.xml文件 14.5 编写内容管理系统的JSP页面 14.5.1 用户注册画面regedit.jsp 14.5.2 用户登录画面login.jsp 14.5.3 设定内容类别画面type.jsp 14.5.4 发布内容画面edit.jsp 14.5.5 浏览内容画面index.jsp 14.6 根据数据库表生成XML和POJO 14.6.1 生成对应的XML 14.6.2 生成POJO 14.7 编写内容管理系统的DAO 14.7.1 用户DAO接口UserDAO.java 14.7.2 内容类别DAO接口ContentTypeDAO.java 14.7.3 内容DAO接口ContentDAO.java 14.7.4 用户DAO实现类UserDAOImpl.java 14.7.5 内容类别DAO实现类ContentTypeDAOImpl.java 14.7.6 内容DAO实现类ContentDAOImpl.java 14.8 编写内容管理系统的业务逻辑类 14.8.1 注册接口Regedit.java 14.8.2 登录接口Login.java 14.8.3 设定内容类别的接口SetContentType.java 14.8.4 发布接口Edit.java 14.8.5 注册实现类RegeditImpl.java 14.8.6 登录实现类LoginImpl.java 14.8.7 设定内容类别的实现类SetContentTypeImpl.java 14.8.8 发布实现类EditImpl.java 14.9 编写内容管理系统的控制器类 14.9.1 登录控制器类LoginAction.java 14.9.2 注册控制器类RegeditAction.java 14.9.3 设定内容类别的控制器类ContentTypeAction.java 14.9.4 发布控制器类EditAction.java 14.9.5 内容控制器类ContentAction.java 14.9.6 浏览内容的控制器类IndexAction.java 14.10 编写Struts的配置文件struts-config.xml 14.11 编写SpringHibernate的配置文件spring-config.xml 14.12 解决Struts的中文乱码问题 14.13 运行验证程序 14.14 小结 第十五章 在线考试系统 15.1 系统概述 15.2 需求分析 15.2.1 系统用例图 15.2.2 需求规格说明书 15.3 系统设计 15.3.1 设计视图层 15.3.2 设计持久层 15.3.3 设计业务逻辑层 15.3.4 设计控制层 15.4 架构设计和环境搭配 15.4.1 在线考试系统采用的架构 15.4.2 在Eclipse下建立项目myExam 15.4.3 编写本项目的Ant文件 15.4.4 配置本项目的web.xml文件 15.5 编写在线考试系统的JSP页面 15.5.1 用户注册画面regedit.jsp 15.5.2 用户登录画面login.jsp 15.5.3 设定试题种类的画面shitiType.jsp 15.5.4 设定试题基本信息的画面shiti.jsp 15.5.5 设定试题项目的画面shitiOption.jsp 15.5.6 组织试卷的画面examInfo.jsp 15.5.7 参加考试的画面exam.jsp 15.5.8 考试成绩的画面examChengji.jsp 15.6 根据数据库表生成XML和POJO 15.6.1 生成对应的XML 15.6.2 生成POJO 15.7 编写在线考试系统的DAO 15.7.1 用户DAO接口UserDAO.java 15.7.2 试题种类DAO接口ShitiTypeDAO.java 15.7.3 试题题目DAO接口ShitiDAO.java 15.7.4 试题项目DAO接口ShitiOptionDAO.java 15.7.5 试卷DAO接口ExamDAO.java 15.7.6 用户DAO实现类UserDAOImpl.java 15.7.7 试题种类DAO实现类ShitiTypeDAOImpl.java 15.7.8 试题题目DAO实现类ShitiDAOImpl.java 15.7.9 试题项目DAO实现类ShitiOptionDAOImpl.java 15.7.10 试卷DAO实现类ExamDAOImpl.java 15.8 编写在线考试系统的业务逻辑类 15.8.1 注册接口Regedit.java 15.8.2 登录接口Login.java 15.8.3 设定试题种类接口SetShitiType.java 15.8.4 设定试题题目接口SetShiti.java 15.8.5 设定试题项目接口SetShitiOption.java 15.8.6 设定试卷接口SetExam.java 15.8.7 注册实现类RegeditImpl.java 15.8.8 登录实现类LoginImpl.java 15.8.9 设定试题种类实现类SetShitiTypeImpl.java 15.8.10 设定试题题目实现类SetShitiImpl.java 15.8.11 设定试题项目实现类SetShitiOptionImpl.java 15.8.12 设定试卷实现类SetExamImpl.java 15.9 编写在线考试系统的控制器类 15.9.1 登录控制器类LoginAction.java 15.9.2 注册控制器类RegeditAction.java 15.9.3 设定试题种类控制器类ShitiTypeAction.java 15.9.4 设定试题题目控制器类ShitiAction.java 15.9.5 设定试题项目控制器类ShitiOptionAction.java 15.9.6 试卷控制器类ExamAction.java 15.10 编写配置文件dispatcherServlet-servlet.xml 15.11 解决Spring的中文乱码问题 15.12 运行验证程序 15.13 小结

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值