• 第三十 访问财富进退自如 —Spring交易管理


              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.jarcommons-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); } }

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




        



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

  • 相关阅读:
    我已经发表的文章:2,《上帝的小蚂蚁》(未经作者本人同意,不得转载!)
    【windows环境下】RabbitMq的安装和监控插件安装
    Apache FtpServer扩展【动手实现自己的业务】
    我的博客开始之旅
    curl和wget的区别和使用 wanglf
    ceph集群部署 wanglf
    ansible实现SSH配置免密互信 wanglf
    kubernetes(k8s) helm安装kafka、zookeeper wanglf
    django项目中使用KindEditor富文本编辑器 wanglf
    下一代网页:当HTML5取代Flash
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4688949.html
Copyright © 2020-2023  润新知