在Spring中实现编程式的事务管理(2)
更新时间:2023-08-11 06:43:01 阅读量: 教育文库 文档下载
- spring编程式事物推荐度:
- 相关推荐
在Spring中实现编程式的事务管理(2)
在Spring中实现编程式的事务管理
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
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提供了几个关于事务处理的类:
TransactionDefinition //事务属性定义
TranscationStatus //代表了当前的事务,可以提交,回滚。
在Spring中实现编程式的事务管理(2)
这些类是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 编程式的事务管理的基本流程
声明数据源
声明一个事务管理类,例如
DataSourceTransactionManager,HibernateTransactionManger,JTATransactionManager等
在我们的代码中加入事务处理代码
(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'");
mit(status);
}
catch(Exception e)
{
transactionManager.rollback(status);
}
在Spring中实现编程式的事务管理(2)
在JBuilder中的本Project中实现Spring的代码控制的事务管理
1、问题:在本项目中再添加一个对用户信息进行修改的功能模块
2、添加一个
updateUserInfo.jsp
在该页面中添加一个表单
<%@ page contentType="text/html; charset=GBK" %>
<html><head><title>updateUserInfo</title></head>
<body bgcolor="#ffffff">
<form action="/SpringMVCWeb/updateUserInfo.do" method="POST">
<input name="menuID" type="hidden" value="3">
请输入用户名称:<input type="text" name="userName"><br>
请输入用户密码:<input type="password" name="userPassWord"><br>
<input type="submit" value="开始修改">
<input type="reset" value="取消修改">
</form>
</body>
</html>
3、修改我们的控制器程序,在其中增加下面的代码(黑体部分)
package springwebapp;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.ModelAndView;
在Spring中实现编程式的事务管理(2)
import javax.servlet.http.HttpServletResponse;
public class UserLoginController extends SimpleFormController {
private UserLoginInterface userLoginImpleBean = null;
public void setUserLoginImpleBean(UserLoginInterface newUserLoginImpleBean) {
userLoginImpleBean = newUserLoginImpleBean;
}
public void setLoginFailure(String loginFailure) {
this.loginFailure = loginFailure;
}
public void setLoginSuccess(String loginSuccess) {
this.loginSuccess = loginSuccess;
}
public UserLoginInterface getUserLoginImpleBean() {
return userLoginImpleBean;
}
public String getLoginFailure() {
return loginFailure;
}
public String getLoginSuccess() {
return loginSuccess;
}
public UserLoginController() {
}
protected ModelAndView onSubmit(Object formBean) throws Exception
{
UserLoginForm userLoginForm = (UserLoginForm) formBean;
ModelAndView targetModelAndView = null;
switch (Integer.parseInt(userLoginForm.getMenuID())) {
case 1: //用户登录
targetModelAndView = doUserLogin(userLoginForm);
break;
case 2: //用户注册
targetModelAndView = doUserRegister(userLoginForm);
break;
case 3: //修改用户信息
targetModelAndView = doUpdateUserInfo(userLoginForm);
break;
}
return targetModelAndView;
}
public ModelAndView doUpdateUserInfo(UserLoginForm userLoginForm)
{
String userName = userLoginForm.getUserName();
String userPassWord = userLoginForm.getUserPassWord();
在Spring中实现编程式的事务管理(2)
oneUserInfoVO.setUserName(userName);
oneUserInfoVO.setUserPassWord(userPassWord);
boolean okOrNot = userLoginImpleBean.doUpdateUserInfo(oneUserInfoVO);
if (okOrNot)
{
return new ModelAndView(this.getUpdateSuccess());
}
else
{
return new ModelAndView(this.getUpdateFailure());
}
}
public ModelAndView doUserRegister(UserLoginForm userLoginForm) {
java.util.Date rightNow = new java.util.Date();
String registerTime = rightNow.toLocaleString();
UserInfoVO userInfo = new UserInfoVO();
userInfo.setUserName( userLoginForm.getUserName());
userInfo.setUserPassWord(userLoginForm.getUserPassWord());
userInfo.setUserDepartment( userLoginForm.getUserDepartment());
userInfo.setUserAdminLevel(Integer.parseInt(userLoginForm.getUserAdminLevel())); userInfo.setDepartAdminLevel(Integer.parseInt(userLoginForm.getUserAdminLevel())); userInfo.setUserImage(userLoginForm.getUserImage());
userInfo.setRegisterTime(registerTime);
boolean okOrNot = userLoginImpleBean.doUserRegister(userInfo);
if (okOrNot) {
return new ModelAndView(registerSuccess);
} else {
return new ModelAndView(registerFailure);
}
}
public ModelAndView doUserLogin(UserLoginForm userLoginForm)
{
String userName = userLoginForm.getUserName();
String userPassWord = userLoginForm.getUserPassWord();
UserInfoVO oneUserInfoVO = new UserInfoVO();
oneUserInfoVO.setUserName(userName);
oneUserInfoVO.setUserPassWord(userPassWord);
boolean okOrNot = userLoginImpleBean.doUserLogin(oneUserInfoVO);
if (okOrNot)
{
return new ModelAndView(getLoginSuccess());
}
else
{
在Spring中实现编程式的事务管理(2)
}
}
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;
}
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;
}
private String loginSuccess;
private String loginFailure;
}
4、修改我们的业务层组件
(1)修改我们的业务接口以增加新的方法定义
package springwebapp;
public interface UserLoginInterface {
public abstract boolean doUserLogin(UserInfoVO oneUserInfo);
public abstract boolean doUserRegister(UserInfoVO oneUserInfo);
public abstract boolean doUpdateUserInfo(UserInfoVO oneUserInfo);
}
在Spring中实现编程式的事务管理(2)
(2)修改我们的业务实现类以增加对该方法的具体实现-----修改用户的信息并采用事务来加以控制
在该类中添加一个transactionManager属性,并且实现我们的带事务处理的方法----事务管理的控制最好应该放到商业逻辑层。我们可以设计一个处理商业逻辑的JavaBean,在该JavaBean中调用DAO,然后把实现商业逻辑的JavaBean的方法纳入Spring的事务管理。
package springwebapp;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContext;
import org.springframework.beans.BeansException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.PlatformTransactionManager;
public class UserLoginImple implements UserLoginInterface,ApplicationContextAware
{
ApplicationListener actionEventResponse = null;
public void setActionEventResponse(ApplicationListener actionEventResponse) {
this.actionEventResponse = actionEventResponse;
}
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public UserLoginImple()
{
}
public boolean doUserRegister(UserInfoVO userInfo)
{
return true;
在Spring中实现编程式的事务管理(2)
public boolean doUpdateUserInfo(UserInfoVO oneUserInfo)
{
String userName=oneUserInfo.getUserName();
String userPassWord=oneUserInfo.getUserPassWord();
Object parameter[]={userPassWord,userName};
//我们需要事务定义,作为示例,我们采用DefaultTransactionDefinition
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
String updateSQL1 = "update userInfo set userPassWord = ? where userName =?"; String updateSQL2 = "update userInfo1 set userPassWord = ? where userName =?"; try
{
this.jdbcTemplate.update(updateSQL1,parameter);
this.jdbcTemplate.update(updateSQL2,parameter);
/*
为了说明事务处理,我们对数据库表进行了两次修改,其中第二次修改应该是失败的(并注意到我們故意在数据库表名称上写错,
这使得SQL句子不合语法,因而造成DataAccessException(它封裝了SQLException),
这个异常被catch捕捉,因而执行rollback()取消前面的正确执行SQL的操作结果,如果沒有发生错误,
则最后我们使用commit()来提交操作。
*/
}
catch (DataAccessException ex)
{
transactionManager.rollback(status); // 也可以执行status.setRollbackOnly(); throw ex;
}
mit(status);
return true;
}
public boolean doUserLogin(UserInfoVO oneUserInfo)
{
boolean okOrNot=false;
String userName=oneUserInfo.getUserName();
String userPassWord=oneUserInfo.getUserPassWord();
String sqlStatement="select * from UserInfo where userName='"+userName+"' and userPassWord ='"+userPassWord+"'";
java.util.List resultRows = jdbcTemplate.queryForList(sqlStatement);
if ((resultRows!=null)&&(resultRows.size() != 0)) //现在已经对对数据库表的访问 {
UserLoginActionEvent userLoginActionEvent = new UserLoginActionEvent(actionEventResponse); //注意指定事件的目标对象
this.applicationContext.publishEvent(userLoginActionEvent); //触发事件
okOrNot=true;
在Spring中实现编程式的事务管理(2)
else
{
okOrNot=false;
}
return okOrNot;
}
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
}
5、修改我们的*.xml配置文件
(1)在springapp-servlet.xml文件中添加下面的与事务相关的一些配置项目
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
(2)修改我们的业务实现类的对象声明
<bean id="userLoginImpleBean" class="erLoginImple">
<property name="actionEventResponse">
<ref bean="actionEventResponse"/>
</property>
<property name="jdbcTemplate">
<ref bean="jdbcTemplate"/>
</property>
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
在Spring中实现编程式的事务管理(2)
(3)修改我们的控制层组件以增加下面的属性
<bean id="userLoginController" class="erLoginController">
<property name="commandClass">
<value>erLoginForm</value>
</property>
<property name="userLoginImpleBean">
<ref bean="userLoginImpleBean"/>
</property>
<property name="updateSuccess">
<value>index</value>
</property>
<property name="updateFailure">
<value>userLogin/updateUserInfo</value>
</property>
<property name="loginSuccess">
<value>userLogin/loginSuccess</value>
</property>
<property name="loginFailure">
<value>userLogin/loginFailure</value>
</property>
<property name="registerSuccess">
<value>userLogin/registerSuccess</value>
</property>
<property name="registerFailure">
<value>userLogin/registerFailure</value>
</property>
</bean>
(4)对我们的<prop key="/updateUserInfo.do">userloginController</prop>加以声明
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
在Spring中实现编程式的事务管理(2)
<props>
<prop key="/hello.do">springappController</prop>
<prop key="/userlogin.do">userloginController</prop>
<prop key="/userRegister.do">userloginController</prop>
<prop key="/updateUserInfo.do">userloginController</prop>
</props>
</property>
</bean>
6、执行该程序,观察数据库表中的数据是否被修改了!
(1)观察数据库表中的用户密码
(2)执行本应用
输入用户名称为admin,但是密码为12345678。
在Spring中实现编程式的事务管理(2)
(3)将出现下面的错误
(4)同时在数据库表中的数据并没有被修改
(5)将代码中的
String updateSQL2 = "update userInfo1 set userPassWord = ? where userName =?";
中的数据库表名称由“userInfo1”改变为正确的“userInfo”,再执行本应用,将能够正确地对用户的密码进行修改。
在Spring中实现编程式的事务管理(2)
采用TransactionTemplate类来简化操作
1、TransactionTemplate类
TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成功后的事务提交。和JdbcTemplate一样,它使得我们无需在琐碎的try/catch/finally代码中徘徊---也就是为我们省去了部分事务提交、回滚代码。
2、修改原来的doUpdateUserInfo方法
public boolean doUpdateUserInfo(UserInfoVO oneUserInfo)
{
String userName=oneUserInfo.getUserName();
String userPassWord=oneUserInfo.getUserPassWord();
Object parameter[]={userPassWord,userName};
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
String updateSQL1 = "update userInfo set userPassWord = ? where userName =?";
String updateSQL2 = "update userInfo1 set userPassWord = ? where userName =?";
/*
下面使用TransactionCallbackWithoutResult,并在它的doInTransactionWithoutResult()中进行SQL操作,如果执行中发生异常,則之前所有的操作将被取消,否则最后自动提交操作。
*/
transactionTemplate.execute(
new TransactionCallbackWithoutResult()
{
public void doInTransactionWithoutResult(TransactionStatus status)
{
this.jdbcTemplate.update(updateSQL1,parameter);
this.jdbcTemplate.update(updateSQL2,parameter);
}
});
return true;
}
(3)说明
在doInTransactionWithoutResult方法中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,则将被自动提交。和JdbcTemplate一样,它使得我们无需在琐碎的try/catch/finally代码中徘徊。
3、如果需要使用基于容器的数据源(JNDI)来实现事务
我们可以采用如下配置,使用JtaTransactionManager,它为PlatformTransactionManager接口的带JNDI数据源的事务实现。
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
在Spring中实现编程式的事务管理(2)
如果我们使用JTA 我们需要使用通过JNDI获得的容器数据源,和一个JtaTransactionManager实 现。 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
默认的Spring JtaTransactionManager设置将从标准的JNDI位置获取JTA的erTransaction对象,该JNDI位置由J2EE指定:java:comp/UserTransaction。对于大多数标准J2EE环境下的用例来说,它工作良好。
但是,默认的JtaTransactionManager不能执行事务挂起操作(即它不支持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED)。原因是标准的JTA UserTransaction接口不支持挂起或恢复事务的操作;它只支持开始和完成新事务的操作。
正在阅读:
改革强警主题教育应知应会04-16
带有虎字的成语11-30
销售助理工作总结2篇(精选多篇)09-28
浮管式水力发电机的社会经济效益08-18
全国2012年4月操作系统概论试题答案05-10
徐口幼儿园消防安全整改报告06-04
工程项目合作洽商会文函06-03
城轨英语期末卷12-13第1学期09-29
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 事务管理
- 程式
- 实现
- Spring