6月16日本,明确。

“应该留给追穷寇勇,不可沽名学霸王。天若有情天亦老,人间正道是沧桑。”

有始有终、有往有还、进退自如乃Spring事务管理之道,也是万物生生不息、和谐共处之道。

遵道而行。但到半途需努力。会心不远,欲登绝顶莫辞劳。

       事务是一个最小的工作单元。不论成功与否都作为一个总体进行工作。

       不会有部分完毕的事务。因为事务是由几个任务组成的,因此假设一个事务作为一个总体是成功的,则事务中的每一个任务都必须成功。假设事务中有一部分失败,则整个事务失败。
       当事务失败时。系统返回到事务開始前的状态。这个取消全部变化的过程称为“回滚”( rollback )。比如,假设一个事务成功更新了两个表。在更新第三个表时失败。则系统将两次更新恢复原状。并返回到原始的状态。

数据库的更新通常都是由客观世界的所发生的事件引起的。

为保证数据库内容的一致,就要将数据库的一组操作作为一个总体来进行。要么所有成功完毕。要么所有失败退出。

假设因为故障或其他原因而使一组操作中有一些完毕。有一些未完毕。则必定会使得数据库中的数据出现不一致,从而使得数据库的完整性受到破坏。因此,更新操作序列必须作为一个总体在DBMS运行时出现。即“要么全做,要么全不做”。SQL提供了事务处理的机制,来帮助DBMS实现上述的功能。

一、以下看一个单纯的spring的声明式(XML 式)事务管理的样例。

1、创建MySQL数据库

见 第十九天 慵懒的投射在JDBC上的暖阳 —Hibernate的使用(一)

由于要演示数据回滚。须要把MySQL默认的ENGINE
= MyISAM改为ENGINE =InnoDB。目的是让数据库支持回滚。

怎样改动,最简单的做法,就是使用Navicat这个工具,设计表—>选项—>表类型

2、创建DAO接口

package edu.eurasia.dao;

public interface TmDao {
public void insert();
public void select();
}

3、创建DAO的实现类

package edu.eurasia.dao;

import java.util.List;

import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport; public class TmDaoImpl extends JdbcDaoSupport implements TmDao {
public void insert() {
try {
super.getJdbcTemplate().update(
"update userinfo set username = '唐伯虎' where id =2");
super.getJdbcTemplate()
.update("INSERT INTO userinfo(username,password) VALUES('李苦禅','88888888')");
super.getJdbcTemplate().update("DELETE FROM userinfo where id =2"); } catch (Exception e) {
logger.error("小心地雷! " + e.getMessage());
e.printStackTrace();
throw new RuntimeException();
// 假设凝视掉throw new RuntimeException。那么事务将不能回滚。由于spring捕捉不到Exception
}
} public void select() {
List list = super.getJdbcTemplate().query("select * from userinfo",
new ColumnMapRowMapper()); System.out.println(list); }
}

4、创建service接口

package edu.eurasia.service;

public interface TmService {
public void insert();
public void select();
}

5、实现service接口

package edu.eurasia.service;

import edu.eurasia.dao.TmDao;

public class TmServiceImpl implements TmService {
private TmDao tmDao; public TmDao getTmDao() {
return tmDao;
} public void setTmDao(TmDao tmDao) {
this.tmDao = tmDao;
} @Override
public void insert() {
tmDao.insert();
} @Override
public void select() {
tmDao.select();
}
}

6、编写spring的配置文件applicationContext.xml

<?

xml version="1.0" encoding="UTF-8"?

>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- 数据源 配置-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/hib? useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean> <!-- 事务管理器 注入dataSource -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- spring提供的操作数据库用的句柄,相似JDBC的Statement类 ,bean能够不写-->
<!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean> --> <!-- 本例中继承了JdbcDaoSupport的父类。它里面有"jdbcTemplate"和"dataSource"的set接口,仅仅需注入随意一个即可了 -->
<bean id="tmDao" class="edu.eurasia.dao.TmDaoImpl">
<!-- <property name="jdbcTemplate" ref="jdbcTemplate" /> -->
<property name="dataSource" ref="dataSource" />
</bean>
<!--  Service配置   -->
<bean id="tmService" class="edu.eurasia.service.TmServiceImpl">
<property name="tmDao" ref="tmDao"></property>
</bean> <!-- 通知器: name="*"是表示切入目标类的全部方法,即TmDao类的全部方法,REQUIRED的意思是在同个方法类的全部sql操作在同一个进程中,这样才干实现回滚操作,dao类里抛出的Exception,所以要求的是凡是发生Exception就回滚-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice> <!-- 切面配置:第一个*表示返回类型,edu.eurasia.dao.表示edu.eurasia.dao包及其他的子包的类,第二个*表示类中的全部方法名,(..)表示随意类型,随意个数的參数 -->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* edu.eurasia.dao.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
</aop:config>
</beans>

7、编写測试类TestTm.java

package edu.eurasia.test;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import edu.eurasia.service.TmService; public class TestTm {
static Logger logger = Logger.getLogger(TestTm.class); @Test
public void tsettm() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
TmService tmservice = (TmService) context.getBean("tmService");
tmservice.insert();
tmservice.select();
}
}

8、执行结果分析

Spring的事务管理默认仅仅对出现执行期异常(java.lang.RuntimeException及其子类)进行回滚。 假设一个方法抛出Exception或者Checked异常。Spring事务管理默认不进行回滚。

所以。DAO的实现类TmDaoImpl.java中要catch
RuntimeException()异常。

仅仅抛出普通exception的话,不会回滚。有的童鞋按上面代码进行測试。发现没有回滚。数据库正常插入一条数据。原因是程序没有异常,须要人为制造一个,比方改动SQL语句"DELETE
FROM userinfo where id1 =2" ,把字段id 改成id1,再试一试,观察控制台你会发现:com.mysql.jdbc.exceptions.MySQLSyntaxErrorException异常抛出。

还有例如以下内容:

log4j.properties的编写见第二十八天 月出惊山鸟 —Spring的AOP

DEBUG [main] (AbstractPlatformTransactionManager.java:821) - Initiating transaction rollback

DEBUG [main] (DataSourceTransactionManager.java:273) - Rolling back JDBC transaction on Connection [com.mysql.jdbc.Connection@9283b0]

再刷新数据库。也不会新插入一条数据。

回滚成功!

注意:像删除或更新一条不存在的记录,类似这些操作,程序是不报异常的,自然不会回滚。能够依据须要自己定义异常。让自己定义的异常继承自RuntimeException。这样抛出的时候才会被Spring默认的事务处理准确处理。

9、环境配置

本例使用spring 2.5.6。除了找出spring.jar,commons-logging-1.1.1.jar两个jar包。外加一个log4j.jar。

还要下载aspectjweaver.jar。

别忘了mysql-connector-java-5.0.8-bin.jar。

项目结构如图:

二、用注解实现事务管理

使用注解来实现声明式事务,这种方法简洁方便。把上面的样例稍加修改就可以。

1、改动配置文件applicationContext.xml,将全部具有@Transactional 注解的bean自己主动配置为声明式事务支持。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- 数据源 配置-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/hib?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean> <!-- 事务管理器 注入dataSource -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- spring提供的操作数据库用的句柄,相似JDBC的Statement类 ,bean能够不写-->
<!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean> --> <!-- 本例中继承了JdbcDaoSupport的父类。它里面有"jdbcTemplate"和"dataSource"的set接口,仅仅需注入随意一个即可了 -->
<bean id="tmDao" class="edu.eurasia.dao.TmDaoImpl">
<!-- <property name="jdbcTemplate" ref="jdbcTemplate" /> -->
<property name="dataSource" ref="dataSource" />
</bean> <!--  Service配置   -->
<bean id="tmService" class="edu.eurasia.service.TmServiceImpl">
<property name="tmDao" ref="tmDao"></property>
</bean> <!-- 用 注解来实现事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>

2、在接口或类的声明处 ,写一个@Transactional。要是仅仅的接口上写, 接口的实现类就会继承下来。

接口的实现类的详细方法,还能够覆盖类声明处的设置。

改动DAO的实现类。加上注解就可以。

package edu.eurasia.dao;

import java.util.List;

import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; @Transactional
public class TmDaoImpl extends JdbcDaoSupport implements TmDao {
@Transactional(propagation=Propagation.REQUIRED,rollbackFor={Exception.class})
public void insert() {
try {
super.getJdbcTemplate().update(
"update userinfo set username = '唐伯虎' where id =3");
super.getJdbcTemplate()
.update("INSERT INTO userinfo(username,password) VALUES('李苦禅','88888888')");
super.getJdbcTemplate().update("DELETE FROM userinfo where id =4"); } catch (Exception e) {
logger.error("小心地雷! " + e.getMessage());
e.printStackTrace();
throw new RuntimeException();
// 假设凝视掉throw new RuntimeException,那么事务将不能回滚,由于spring捕捉不到Exception
}
} public void select() {
List list = super.getJdbcTemplate().query("select * from userinfo",
new ColumnMapRowMapper()); System.out.println(list); }
}

执行效果和上面的样例是一致的。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

第三十 访问财富进退自如 —Spring交易管理的更多相关文章

  1. SpringCloud微服务实战——搭建企业级开发框架(三十六):使用Spring Cloud Stream实现可灵活配置消息中间件的功能

      在以往消息队列的使用中,我们通常使用集成消息中间件开源包来实现对应功能,而消息中间件的实现又有多种,比如目前比较主流的ActiveMQ.RocketMQ.RabbitMQ.Kafka,Stream ...

  2. Spring Security(三十六):12. Spring MVC Test Integration

    Spring Security provides comprehensive integration with Spring MVC Test Spring Security提供与Spring MVC ...

  3. Expo大作战(三十)--expo sdk api之Permissions(权限管理模块),Pedometer(计步器api)

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  4. 第二百三十节,jQuery EasyUI,后台管理界面---后台管理

    jQuery EasyUI,后台管理界面---后台管理 一,admin.php,后台管理界面 <?php session_start(); if (!isset($_SESSION['admin ...

  5. 一百三十四:CMS系统之版块管理二

    编辑 html,将数据渲染到tr上,方便js取值 js //编辑板块$(function () { $('.edit-board-btn').click(function (event) { var ...

  6. 精选Spring Boot三十五道必知必会知识点

    Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家.本文精选了三十五个常见的Spring Boot知识点,祝你一臂之力! 问题一 Spr ...

  7. SpringBoot:三十五道SpringBoot面试题及答案

    SpringBoot面试前言今天博主将为大家分享三十五道SpringBoot面试题及答案,不喜勿喷,如有异议欢迎讨论! Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一 ...

  8. spring boot 常见三十四问

    Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...

  9. 面渣逆袭:Spring三十五问,四万字+五十图详解

    大家好,我是老三啊,面渣逆袭 继续,这节我们来搞定另一个面试必问知识点--Spring. 有人说,"Java程序员都是Spring程序员",老三不太赞成这个观点,但是这也可以看出S ...

随机推荐

  1. 前台技术--通过javaScript提交表单

    window.location=pp+"?username="+getCookie("username")+"&userid="+g ...

  2. UVA11100- The Trip, 2007

    option=com_onlinejudge&Itemid=8&category=512&page=show_problem&problem=2041"> ...

  3. C++学习笔记33 转换操作符

    有时候,我们要转换为类类型和类类型,同时,这两个类继承关系不存在,这时候我们就需要一些所谓的转换操作符运营商. 一个简单的例子.类别A转换为int种类 #include <iostream> ...

  4. simpleDateFormat日期格式转换

    1------------------------------------------------------------------------------------- package com.n ...

  5. java中间==、equals和hashCode差额

    java于==.equals().hashCode()和比较两个对象. 关于== ==是easy理解的.java设计java就是要比較两个对象是不是同一个对象. 对于引用变量而言.比較的时候两个引用变 ...

  6. HttpClient文件上传下载

    1 HTTP HTTP 协议可能是如今 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序须要直接通过 HTTP 协议来訪问网络资源. 尽管在 JDK 的 java.net ...

  7. asp.net在用户控件中使用ClientScript

    在用户空间中调用ClientScript.RegisterClientScriptBlock方法 ClientScript的命名空间是System.Web.UI.Page,并且要实例化之后的Page才 ...

  8. STM32本学习笔记EXTI(外部中断)

    参考资料:STM32数据表.网络信息 =========================================切割线===================================== ...

  9. poj 3074 Sudoku(Dancing Links)

    Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8152   Accepted: 2862 Descriptio ...

  10. Android - match_parent 和 fill_parent差异

    Android - match_parent 和 fill_parent差异 本文地址: http://blog.csdn.net/caroline_wendy match_parent 和 fill ...