1.1在Spring框架中实现编程式的事务管理的应用实例(Eclipse版本第1部分)
1.1.1传统的JDBC事务管理相关的应用技术
1、编程式的事务管理实现----传统的JDBC事务管理
(1)对每个请求都是从数据源中重新取出一个连接
以往使用JDBC进行数据操作时,一般采用DataSource,从数据源中得到Connection,我们知道数据源DataSource是线程安全的,而数据连接对象Connection不是线程安全的,所以对每个请求都是从数据源中重新取出一个连接。
一般的数据源由容器进行管理,包括连接池。例如TOMCAT,WEBSPHERE,WEBLOGIC等这些J2EE商业容器都提供了这个功能。
(2)JDBC标准的事务管理实现的代码
Connection conn = null;
try
{
conn = DBConnectionFactory.getConnection;
conn.setAutoCommit(false); //(1) 缺省方式是自动提交
//完成对数据库的修改操作
Update
update
https://www.sodocs.net/doc/e2705297.html,mit(); //(2)自己提交
}
catch(Exception e)
{
conn.rollback(); //(3) 恢复修改
//do sth
}
finally
{
try
{
conn.close();
}
catch(SQLException se)
{
//do sth
}
}
(3)JDBC标准的事务管理实现的代码的缺点
按照以往的思路来写代码,不仅代码量比较长,而且也很容易疏忽或者忘掉一些try/catch语句,引发一些异常无法catch,因此,我们会写DBTool类,来关闭这些资源,并且保证在关闭这些资源时,不向外抛异常。
2、Spring JdbcTemplate的缺省的事务管理模式
(1)Spring为我们对JDBC事务管理模式进行包装,从而在一定的程度上简化了编程Spring提供了几个关于事务处理的类:
1)TransactionDefinition //事务属性定义
2)TranscationStatus //代表了当前的事务,可以提交,回滚。
3)PlatformTransactionManager
这些类是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
(2)JdbcTemplate的缺省的事务管理模式采用的是JDBC默认的AutoCommit模式前面的例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还无法保证数据操作的原子性(要么全部生效,要么全部无效)。如下面的操作:JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = '1234'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = '1234'");
由于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库中
"1234"对应的记录已经被更新,如果第二个操作失败,我们无法使得整个事务回滚到最初状态。
对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致致命错误。为了实现数据操作的原子性,我们需要在程序中引入事务逻辑。
(3)利用DataSourceTransactionManager类实现代码控制的事务管理
org.springframework.jdbc.datasource.DataSourceTransactionManager类为JDBC DataSource类型的数据源的事务管理组件。
只需要在Bean的定义配置的*.xml文件中对它进行配置,然后将其引入到我们的DAO 类中。
(4)使用Spring 编程式的事务管理的基本流程
1)声明数据源
2)声明一个事务管理类,例如
DataSourceTransactionManager,HibernateTransactionManger,JTATransactionManager
等
3)在我们的代码中加入事务处理代码
(5)代码示例如下
TransactionDefinition td = new TransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(td);
try
{
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = '1234'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = '1234'");
https://www.sodocs.net/doc/e2705297.html,mit(status);
}
catch(Exception e)
{
transactionManager.rollback(status);
}
1.1.2在Eclipse中的本Project中实现Spring的代码控制的事务管理
1、问题:什么场合需要考虑“事务”支持
在本项目中再添加一个对用户信息进行修改的功能模块。
2、添加一个updateUserInfo.jsp
(1)添加一个updateUserInfo.jsp页面文件
(2)在该页面中添加一个表单
(3)updateUserInfo.jsp页面文件中相关的HTML代码
<%@ page contentType="text/html; charset=GBK" %>
3、修改我们的UserLoginForm类增加一个,并且为它提供 get/set方法
private String newUserPassWord;
4、修改控制器程序,在其中增加下面的代码(黑体部分)
package com.px1987.springwebapp.control;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.px1987.springwebapp.model.*;
import com.px1987.springwebapp.view.*;
public class UserManageController extends SimpleFormController
{
private String loginSuccess;
private String loginFailure;
private UserManageInterface userLoginImpleBean=null;
@Override
protected ModelAndView onSubmit(Object loginFormBean) throws Exception {
UserLoginForm userFormBean=(UserLoginForm)loginFormBean;
String menuID=userFormBean.getMenuID();
ModelAndView oneModelAndView=null;
switch(Integer.parseInt(menuID))
{
case 1: //login
oneModelAndView=doUserLogin(userFormBean );
break;
case 2: //Register
oneModelAndView=doUserRegister(userFormBean );
break;
case 3: //修改用户信息
oneModelAndView = doUpdateUserInfo(userFormBean);
break;
}
throw new Exception(); //未实现声明的异常
// return oneModelAndView;
}
public ModelAndView doUpdateUserInfo(UserLoginForm userLoginForm) {
String userName = userLoginForm.getUserName();
String userPassWord = userLoginForm.getUserPassWord();
String newUserPassWord = userLoginForm.getNewUserPassWord();
UserInfoVO oneUserInfoVO = new UserInfoVO();
oneUserInfoVO.setUserName(userName);
oneUserInfoVO.setUserPassWord(userPassWord);
boolean okOrNot = userLoginImpleBean.doUpdateUserInfo(oneUserInfoVO,newUserPassWord);
if (okOrNot)
{
return new ModelAndView(this.getUpdateSuccess());
}
else
{
return new ModelAndView(this.getUpdateFailure());
}
}
public ModelAndView doUserLogin(UserLoginForm userLoginForm )
{
// (1)获得请求参数
String userName=userLoginForm.getUserName();
String userPassWord=userLoginForm.getUserPassWord();
// (2)对业务功能组件进行调用以完成指定的功能实现
UserInfoVO oneUserInfoVO=new UserInfoVO();
oneUserInfoVO.setUserName(userName);
oneUserInfoVO.setUserPassWord(userPassWord);
boolean okOrNot=userLoginImpleBean.doUserLogin(oneUserInfoVO);
// (3)对业务功能组件处理后的结果进行调度
if(okOrNot)
{
return new ModelAndView(loginSuccess);
}
else
{
return new ModelAndView(loginFailure);
}
}
public ModelAndView doUserRegister(UserLoginForm userRegisterForm )
{
java.util.Date rightNow = new java.util.Date();
String registerTime = rightNow.toLocaleString();
UserInfoVO userInfo = new UserInfoVO();
userInfo.setUserName(userRegisterForm.getUserName());
userInfo.setUserPassWord(userRegisterForm.getUserPassWord());
userInfo.setUserDepartment( userRegisterForm.getUserDepartment()); userInfo.setUserAdminLevel(Integer.parseInt(userRegisterForm.getUserAdminLevel ()));
userInfo.setDepartAdminLevel(Integer.parseInt(userRegisterForm.getUserAdminLev el()));
userInfo.setUserImage(userRegisterForm.getUserImage());
userInfo.setRegisterTime(registerTime);
boolean okOrNot= userLoginImpleBean.doUserRegister(userInfo);
if(okOrNot){
return new ModelAndView(registerSuccess);
}
else{
return new ModelAndView(registerFailure);
}
}
public UserManageController(){
}
private String registerSuccess;
private String registerFailure;
public String getRegisterSuccess() {
return registerSuccess;
}
public void setRegisterSuccess(String registerSuccess) {
this.registerSuccess = registerSuccess;
}
public String getRegisterFailure() {
return registerFailure;
}
public void setRegisterFailure(String registerFailure) {
this.registerFailure = registerFailure;
}
public String getLoginFailure() {
return loginFailure;
}
public void setLoginFailure(String loginFailure) {
this.loginFailure = loginFailure;
}
public String getLoginSuccess() {
return loginSuccess;
}
public void setLoginSuccess(String loginSuccess) {
this.loginSuccess = loginSuccess;
}
public void setUserLoginImpleBean(UserManageInterface userLoginImpleBean) { https://www.sodocs.net/doc/e2705297.html,erLoginImpleBean = userLoginImpleBean;
}
private String updateSuccess;
private String updateFailure;
public String getUpdateFailure() {
return updateFailure;
}
public String getUpdateSuccess() {
return updateSuccess;
}
public void setUpdateSuccess(String updateSuccess) {
this.updateSuccess = updateSuccess;
}
public void setUpdateFailure(String updateFailure) {
this.updateFailure = updateFailure;
}
}
5、修改示例中的业务层组件
(1)修改我们的业务接口以增加新的方法定义
package com.px1987.springwebapp.model;
public interface UserManageInterface
{
public abstract boolean doUserLogin(UserInfoVO oneUserInfo);
public abstract boolean doUserRegister(UserInfoVO oneUserInfo);
public boolean doUpdateUserInfo(UserInfoVO userInfo ,String newUserPassWord);
}
(2)修改我们的业务实现类以增加对该方法的具体实现
package com.px1987.springwebapp.model;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ApplicationContextAware;
import com.px1987.springwebapp.event.*;
import com.px1987.springwebapp.dao.*;
public class UserManageImple implements UserManageInterface,ApplicationContextAware
{
private DAOInterface daoImpleObject=null;
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
ApplicationListener actionEventResponse=null; //代表事件响应者
public void setActionEventResponse(ApplicationListener actionEventResponse)
{
this.actionEventResponse = actionEventResponse;
}
public UserManageImple() {
}
public boolean doUpdateUserInfo(UserInfoVO oneUserInfoVO ,String newUserPassWord)
{
boolean okOrNot=false;
okOrNot=daoImpleObject.updateOneUserInfo(oneUserInfoVO,
newUserPassWord);
return okOrNot;
}
public boolean doUserRegister(UserInfoVO userInfo )
{
boolean okOrNot=daoImpleObject.insertOneUserInfo(userInfo);
if(okOrNot)
{
UserLoginActionEvent userLoginActionEvent = new UserLoginActionEvent(actionEventResponse); //注意指定事件的目标对象 this.applicationContext.publishEvent(userLoginActionEvent); //触发事件
}
return okOrNot;
}
public boolean doUserLogin(UserInfoVO oneUserInfo) //“业务处理”
{
boolean okOrNot=false;
String userName=oneUserInfo.getUserName();
String userPassWord=oneUserInfo.getUserPassWord();
UserInfoVO returnOneUserInfo=daoImpleObject.selectUserInfo(userName, userPassWord);
if(returnOneUserInfo==null)
{
okOrNot=false;
}
else
{
okOrNot=true;
}
return okOrNot;
}
public void setDaoImpleObject(DAOInterface daoImpleObject) {
this.daoImpleObject = daoImpleObject;
}
}
6、修改示例DAO中的各个组件
(1)修改DAO的接口DAOInterface,并增加一个方法的定义
package com.px1987.springwebapp.dao;
import com.px1987.springwebapp.model.*;
public interface DAOInterface
{
public UserInfoVO selectUserInfo(String userName, String userPassWord);
public boolean insertOneUserInfo(UserInfoVO oneUserInfoVO);
public boolean deleteOneUserInfo(int userID);
public boolean updateOneUserInfo(UserInfoVO oneUserInfoVO);
public boolean updateOneUserInfo(UserInfoVO oneUserInfoVO,String newUserPassWord);
}
(2)修改我们的接口DAOInterface实现类以增加对该方法的具体实现
package com.px1987.springwebapp.dao;
import https://www.sodocs.net/doc/e2705297.html,erInfoVO;
import org.springframework.jdbc.core.*;
import java.util.*;
public class DAOImple implements DAOInterface
{
JdbcTemplate jdbcTemplate=null;
public DAOImple(){
}
public boolean deleteOneUserInfo(int userID)
{
return false;
}
public boolean insertOneUserInfo(UserInfoVO oneUserInfoVO) {
String insertStatement="insert into UserInfo values(?,?,?,?,?,?,?,?)";
java.util.Date now=new java.util.Date();
Object userInfoParameter[]={
oneUserInfoVO.getUserName(),
oneUserInfoVO.getUserPassWord(),
oneUserInfoVO.getUserDepartment(), new
Integer(oneUserInfoVO.getUserAdminLevel()),
new
Integer(oneUserInfoVO.getDepartAdminLevel()),
oneUserInfoVO.getUserImage(),
oneUserInfoVO.getRegisterTime(),
new Integer((int)now.getTime())
};
boolean okOrNot=false;
int
returnCount=jdbcTemplate.update(insertStatement,userInfoParameter);
if(returnCount!=0)
{
okOrNot=true;
}
else
{
okOrNot=false;
}
return okOrNot;
}
public UserInfoVO selectUserInfo(String userName, String userPassWord) {
UserInfoVO oneUserInfoVO=null;
// String sqlStatement="select * from UserInfo where userName='"+userName+"' and userPassWord ='"+ userPassWord+"'";
String sqlStatement="select * from UserInfo where userName=? and userPassWord =?";
Object userInfoPara[]={ userName,
userPassWord
};
java.util.List resultRows = jdbcTemplate.queryForList(sqlStatement,userInfoPara);
if ((resultRows!=null)&&(resultRows.size() != 0)) //现在已经对对数据库表的访问
{
Map oneUserMap = (Map) resultRows.get(0);
String returnUserName=(String)oneUserMap.get("userName");
String returnUserPassWord=(String)oneUserMap.get("userPassWord");
oneUserInfoVO=new UserInfoVO();
oneUserInfoVO.setUserName(returnUserName);
oneUserInfoVO.setUserPassWord(returnUserPassWord)
}
else
{
oneUserInfoVO=null;
}
return oneUserInfoVO;
}
public boolean updateOneUserInfo(UserInfoVO oneUserInfoVO)
{
return false;
}
public boolean updateOneUserInfo(UserInfoVO oneUserInfoVO,String newUserPassWord){
String userName=oneUserInfoVO.getUserName();
String userPassWord=oneUserInfoVO.getUserPassWord();
Object parameter[]={newUserPassWord,userName,userPassWord};
String updateSQL1 = "update userInfo set userPassWord = ? where userName =? and userPassWord=?";
this.jdbcTemplate.update(updateSQL1,parameter);
return true;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
7、再增加另外两个页面——updateSuccess.jsp代表修改成功的提示结果信息的页面(1)增加updateSuccess.jsp页面
(2)updateSuccess.jsp页面内的HTML标签的内容如下
<%@ page contentType="text/html; charset=GBK" %>
8、再增加另外两个页面——updateFailure.jsp代表修改失败的提示结果信息的页面(1)增加updateFailure.jsp页面
(2)updateFailure.jsp页面内的HTML标签的内容如下
<%@ page contentType="text/html; charset=GBK" %>
9、修改项目中的Spring IOC配置相关的*.xml文件
(1)在springapp-servlet.xml中定义修改信息的表单与控制器之间的关联
(2)在userManager.xml中增加下面的属性定义和注入
"https://www.sodocs.net/doc/e2705297.html,/dtd/spring-beans-2.0.dtd">
10、将本示例的应用进行部署然后再进行测试
(1)出现下面的页面
(2)出现成功的提示
(3)同时在数据库表中应该出现下面的结果