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. Spring系列

    Spring系列之访问数据库   阅读目录 一.概述 二.JDBC API的最佳实践 三.Spring对ORM的集成 回到顶部 一.概述 Spring的数据访问层是以统一的数据访问异常层体系为核心,结 ...

  2. vs2015 安装问题汇总

    1. The product version that you are trying to set up is earlier than the version already installed o ...

  3. vultr centos x64 6.5.x 升级php7.0

    升级前,先卸载 php5.6.x 卸载php5.6.2 从cent 6.5.x 需要卸载: yum remove php56u-mysqlnd-5.6.20-1.ius.centos6.x86_64 ...

  4. java打印各种菱形

    /** * 类说明 * * @author 曾修建 * @version 创建时间:2014-7-23 上午09:50:46 */ public class Diamond { public stat ...

  5. ViewPager空指针错误,android.support.v4.view.ViewPager.onSaveInstanceState

    support.v4 包为我们提供了一个非常实用的滑动控件ViewPager,在使用ViewPager时有一个需要注意的地方: 即: android.support.v4.view.ViewPager ...

  6. 创Wcf案例数据服务

    首先,创建实体类: using System; using System.Linq; using System.Collections.Generic; using System.Data.Servi ...

  7. C#Process执行批处理后如何获取返回值?

    代码如下   p.StartInfo = new System.Diagnostics.ProcessStartInfo(path, pwd); p.Start();其中path是个BAT的路径!我想 ...

  8. J2SE基础:7.系统经常使用类一

    1.Object对象 Object对象是全部对象的根类. 每一个对象都默认继承自Object类. equals():对象与对象之间是否相等. 逻辑上面的相等.equals 物理上面的相等(地址相等) ...

  9. 4.锁定--Java的LockSupport.park()实现分析

    LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了主要的线程同步原语. LockSupport实际上是调用了Unsafe类里的函数.归结到Unsafe里,仅仅有两个函数: ...

  10. 发现SQL Server惊天大秘密!!

    原文:发现SQL Server惊天大秘密!! --set statistics xml onCREATE TABLE T_TEST(ID INT IDENTITY PRIMARY KEY,Create ...