Spring详解四之声明式事务

1、声明式事务

2Spring事务引入的分析------PlatformTransactionManager类简单介绍

3、注解式事务声明

4xml配置式事务声明

5Spring整合Web

1、声明式事务

事务分为声明式和编程式两种:

声明式事务:声明式事务是指通过注解的形式对事务的各种特性进行控制和管理。

编码式(编程式)事务:指的是通过编码的方式实现事务的声明。

 

1.1、编码方式实现事务:


1.2、声明式事务环境搭建

1.2.2、准备测试数据库


##创建tx数据库
drop database if exists `tx`;
CREATE database `tx`;
##切换tx数据库
USE `tx`;

##删除用户表
DROP TABLE IF EXISTS `user`;
##创建用户表
CREATE TABLE `user` (
  `id` int primary key auto_increment,	
  `username` varchar(50) NOT NULL,
  `money` int(11) DEFAULT NULL
);
##插入数据
insert  into `user`(`username`,`money`) values ('张三',1000),('李四',1000);

##删除图书表
drop table if exists `book`;
##创建图书表
create table `book`(
    `id` int primary key auto_increment,
    `name` varchar(500) not null,
    `stock` int
);
##插入数据
insert into book(`name`,`stock`) values('java编程思想',100),('C++编程思想',100);

##查看数据
select * from book;
select * from user;

1.2.2、创建一个Java工程,导入Jar


JavaBean对象


public class Book {

	private Integer id;
	private String name;
private int stock;

public class User {

	private Integer id;
	private String username;
	private int money;

Dao

@Repository
public class BookDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	public int updateBook() {
		String sql = "update book set name = '**我被修改了!**' where id = 1";
		return jdbcTemplate.update(sql);
	}

}

@Repository
public class UserDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	public int updateUser() {
		String sql = "update user set username = '**我被修改了**' where id = 1";
		return jdbcTemplate.update(sql);
	}

}

Service代码

@Service
public class TransactionService {

	@Autowired
	private UserDao userDao;

	@Autowired
	private BookDao bookDao;

	public void updateTwoTable() {
		userDao.updateUser();
		bookDao.updateBook();
	}

}

1.3测试Service的默认事务

实验1:测试service服务层的默认事务

@ContextConfiguration(locations = "classpath:application.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringTest {

	@Autowired
	private DataSource dataSource;

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	private TransactionService transactionService;

	@Test
	public void testDataSource() throws Exception {
		System.out.println(dataSource.getConnection());
	}
	
	@Test
	public void testJdbcTempalte() throws Exception {
		System.out.println( jdbcTemplate );
	}
	
	@Test
	public void testTransaction() throws Exception {
		transactionService.updateTwoTable();
	}

}

异常的演示

public void updateTwoTable() {
		userDao.updateUser();
		int i = 12 / 0;
		bookDao.updateBook();
	}

结果:

但结果却是一张表更新了,另一种表未更新就发生异常,导致两张表不能同步,经典案例就是银行的转账,这边转过去了,对方没有收到。这里就要用到事务来处理了,要是在同一个事务中有一处出错,整个事务都回滚,从而阻止这种非一致性的更新操作。


2Spring事务引入的分析------PlatformTransactionManager类简单介绍

 

PlatformTransactionManager接口,提供所有事务操作规范。我们使用DataSource数据库连接池,使用的事务管理器是DataSourceTransactionManager



注:和JavawebFilterjdk动态代理、aopUtilsjdbc的原理一样分三层结构处理业务

3、注解式事务声明

3.1使用Spring的注解式声明事务管制

实验2:测试Spring的声明式事务

 

先导入AOP包,因为Spring的底层事务使用到了aop功能

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

配置Spring的事务需要的切面类DataSourceTransactionManager


	<!-- 配置DataSourceTransactionManager事务管理器===事务的切面类 -->
	<bean id="transactionManager" 
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />	
	</bean>

Spring的配置文件中加入tx名称空间


在Spring的配置文件中


<!-- 配置启用spring的事务注解驱动@Transactional -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

还需要在Service的事务方法中添加@Transactioaln注解

@Transactional
	public void updateTwoTable() {
		userDao.updateUser();
		int i = 12 / 0;
		bookDao.updateBook();
	}

3.2noRollbackFornoRollbackForClassName测试不回滚的异常

实验3noRollbackFornoRollbackForClassName测试不回滚的异常

/**
	 * noRollbackFor=ArithmeticException.class 表示当接收到数学异常之后。不回滚<br/>
	 * noRollbackForClassName="java.lang.ArithmeticException" 表示当接收到指定字符串表示的全类名的异常的时候,不回滚事务
	 */
	@Transactional(noRollbackFor=ArithmeticException.class)
	public void updateTwoTable() {
		userDao.updateUser();
		int i = 12 / 0;
		bookDao.updateBook();
	}

Book:


User表:


注:spring默认回滚的是运行时异常RuntimeExceptionRuntimeException的子异常


3.3、自定义设置回滚异常

实验5rollbackForrollbackForClassName回滚的异常

Spring默认回滚的是RuntimeException,运行时异常或运行时异常的子异常


/**
	 * spring默认回滚的是运行时异常RuntimeException和RuntimeException的子异常<br/>
	 * rollbackFor=FileNotFoundException.class	表示FileNotFoundException也会回滚
	 * rollbackForClassName="java.io.FileNotFoundException" 表示当出现配置字符串所表示的全类名的异常的时候。也会回滚事务
	 * @throws FileNotFoundException
	 * 
	 */
	@Transactional(rollbackFor=FileNotFoundException.class)
	public void updateTwoTable() throws FileNotFoundException {
		userDao.updateUser();
		int i = 0;
		if (i == 0) {//java.io.FileNotFoundException
			throw new FileNotFoundException("sadf");
		}
		bookDao.updateBook();
	}

3.3、事务的只读属性

实验4:测试readOnly只读属性

/**
	 * readOnly 如果值为true。表示只支持查询操作。不支持写操作
* <br/>如果设置为false,支持全部
	 */
	@Transactional(readOnly=true)
	public void updateTwoTable() throws FileNotFoundException {
		userDao.updateUser();
		bookDao.updateBook();
	}


3.4、事务超时属性timeout(秒为单位)

timeout=3表示操作不能超过3秒,否在就包错


@Transactional(timeout=3)
	public void updateTwoTable() throws FileNotFoundException {
		userDao.updateUser();
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		bookDao.updateBook();
	}

3.5、事务的传播特性propagation

什么是事务的传播行为:

当事务方法(XxxService())被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为。

 

事务的传播特性,有以下几种类型:(常用的就前两种,所以下面进行这两种的测试)required默认的


3.6、注解演示事物传播特性

因为事务方法是被其他事务方法调用所以,添加几个事务方法进行测试

UserService

BookService

TransactionService

实验1:大小事务传播特性都是REQUIRED

实验2:大小事务传播特性都是REQUIRES_NEW

实验3:大事务是REQUIRED,小事务都是REQUIRES_NEW

实验4:大事务是REQUIRED,小1REQUIRED,小2REQUIRES_NEW

实验5:大事务是REQUIRED,小1REQUIRES_NEW,小2REQUIRED

实验1:大小事务传播特性都是REQUIRED

	@Transactional(propagation = Propagation.REQUIRED)
	public void multiUpdate() {
	@Transactional(propagation = Propagation.REQUIRED)
	public void updateBook() {
        @Transactional(propagation=Propagation.REQUIRED)
        public void updateUser() {

实验2:大小事务传播特性都是REQUIRES_NEW


	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void multiUpdate()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateBook()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateUser()

实验3:大事务是REQUIRED,小事务都是REQUIRES_NEW


	@Transactional(propagation = Propagation.REQUIRED)
	public void multiUpdate()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateBook()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateUser()

实验4:大事务是REQUIRED,小1REQUIRED,小2REQUIRES_NEW


	@Transactional(propagation = Propagation.REQUIRED)
	public void multiUpdate()
	@Transactional(propagation = Propagation.REQUIRED)
	public void updateBook()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateUser()

实验5:大事务是REQUIRED,小1REQUIRES_NEW,小2REQUIRED


	@Transactional(propagation = Propagation.REQUIRED)
	public void multiUpdate()
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void updateBook()
	@Transactional(propagation = Propagation.REQUIRED)
	public void updateUser()

4xml配置式事务声明

去掉。所有@Transactional的注解。

当然注解有的功能,xml也可以实现


<!-- 配置DataSourceTransactionManager事务管理器===事务的切面类 -->
	<bean id="transactionManager" 
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />	
	</bean>

	<!-- 事务特性 -->
	<tx:advice id="tx_advice" transaction-manager="transactionManager">
		<!-- 配置事务特性 -->
		<tx:attributes>
			<tx:method name="multiUpdate" propagation="REQUIRED"/>
			<tx:method name="updateBook" propagation="REQUIRES_NEW"  />
			<tx:method name="updateUser" propagation="REQUIRED"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>

	<!-- 配置aop代理,一定要有切入点表达式 -->
	<aop:config>
		<aop:advisor advice-ref="tx_advice" pointcut="execution(* com.atguigu.service.*Service.*(..))" />
	</aop:config>

总结:使用jdbcTemplate或者是事务管理器 属性都要引用数据源,因为都是在数据库连接的基础上操作的。

总结:注解方式和配置文件方式的事务

(1)、无论哪种方式,默认都是propagation="REQUIRED"方式

(2)、无论哪种方式,默认值都是:transaction-manager="transactionManager"

3)、无论哪种方式,都要有事务管理器---管理事务的切面类-DataSourceTransactionManager

advice - advisor :建议 ,顾问

配置文件情况下:一、(为什么用aop.jar包?因为事务的底层是用aop的三层结构实现的,学习aop的主要作用就是处理事务)

<!-- 配置aop代理 -->
	<aop:config>
		<aop:advisor advice-ref="tx_advice" pointcut="execution(* com.atguigu.service.*Service.*(..))" />
	</aop:config>

二、还有事务的特性配置

注解方法情况下:在Spring的配置文件中

<!-- 配置		启用spring的事务(tx:)		注解(annotation)	驱动(driven )@Transactional -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

这里的transaction-manager="transactionManager"一般如果切面类的id值是transactionManager,这里就可以省略了,阴谋在事务的注解驱动里,默认是这个值的。但如果切面类的管理器的id不是这个值,这里就一定要加上对应的值了。

5Spring整合Web

5.1在web工程中添加Springjar包。

Spring的核心包

spring-beans-4.0.0.RELEASE.jar

spring-context-4.0.0.RELEASE.jar

spring-core-4.0.0.RELEASE.jar

spring-expression-4.0.0.RELEASE.jar

aop

spring-aop-4.0.0.RELEASE.jar(注解,包扫描)

spring-aspects-4.0.0.RELEASE.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

JDBC-ORM

spring-jdbc-4.0.0.RELEASE.jar

spring-orm-4.0.0.RELEASE.jar

spring-tx-4.0.0.RELEASE.jar(事务管理)

Springweb整合包

spring-web-4.0.0.RELEASE.jar

测试包

spring-test-4.0.0.RELEASE.jar

 

 

整合SpringWeb容器分两个步骤:

1、导入spring-web-4.0.0.RELEASE.jar

2、在web.xml配置文件中配置org.springframework.web.context.ContextLoaderListener(直接提示导入,无需记忆)监听器监听ServletContext的初始化

3、在web.xml配置文件中配置contextConfigLocation上下文参数。配置Spring配置文件的位置,以用于初始化Spring容器

5.2在web.xml中配置

  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

5.3获取WebApplicationContext上下文对象的方法如下:

方法一(官方推荐):

WebApplicationContextUtils.getWebApplicationContext(getServletContext())

 

 

方法二(不推荐):

getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);


Spring详解三之AOP与数据访问
常用spring开发jar包即额外包下载


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值