1、声明式事务
2、Spring事务引入的分析------PlatformTransactionManager类简单介绍
3、注解式事务声明
4、xml配置式事务声明
5、Spring整合Web
1、声明式事务
事务分为声明式和编程式两种:
声明式事务:声明式事务是指通过注解的形式对事务的各种特性进行控制和管理。
编码式(编程式)事务:指的是通过编码的方式实现事务的声明。
1.1、编码方式实现事务:
![](https://i-blog.csdnimg.cn/blog_migrate/f5c986a8087e3ce406fc923249a3b68b.png)
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包
![](https://i-blog.csdnimg.cn/blog_migrate/8553891c74d717c711170038f0ad0b88.png)
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();
}
结果:
但结果却是一张表更新了,另一种表未更新就发生异常,导致两张表不能同步,经典案例就是银行的转账,这边转过去了,对方没有收到。这里就要用到事务来处理了,要是在同一个事务中有一处出错,整个事务都回滚,从而阻止这种非一致性的更新操作。
![](https://i-blog.csdnimg.cn/blog_migrate/4467bb562d807bf42a25e00875c94c26.png)
2、Spring事务引入的分析------PlatformTransactionManager类简单介绍
PlatformTransactionManager接口,提供所有事务操作规范。我们使用DataSource数据库连接池,使用的事务管理器是DataSourceTransactionManager类
![](https://i-blog.csdnimg.cn/blog_migrate/8c17c5dd4d51ce7d6a707eb6d55fd02a.png)
注:和Javaweb的Filter、jdk动态代理、aop、Utilsjdbc的原理一样分三层结构处理业务
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名称空间
![](https://i-blog.csdnimg.cn/blog_migrate/1b561affab6f1a36df7010da7e09a9a2.png)
在Spring的配置文件中
<!-- 配置启用spring的事务注解驱动@Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/>
还需要在Service的事务方法中添加@Transactioaln注解
@Transactional
public void updateTwoTable() {
userDao.updateUser();
int i = 12 / 0;
bookDao.updateBook();
}
3.2、noRollbackFor和noRollbackForClassName测试不回滚的异常
实验3:noRollbackFor和noRollbackForClassName测试不回滚的异常
/**
* noRollbackFor=ArithmeticException.class 表示当接收到数学异常之后。不回滚<br/>
* noRollbackForClassName="java.lang.ArithmeticException" 表示当接收到指定字符串表示的全类名的异常的时候,不回滚事务
*/
@Transactional(noRollbackFor=ArithmeticException.class)
public void updateTwoTable() {
userDao.updateUser();
int i = 12 / 0;
bookDao.updateBook();
}
Book:
![](https://i-blog.csdnimg.cn/blog_migrate/7bd21f5853d7a40d1ec311f986270fb2.png)
User表:
![](https://i-blog.csdnimg.cn/blog_migrate/b24b54ef0aef74a62b7d08f839262565.png)
注:spring默认回滚的是运行时异常RuntimeException和RuntimeException的子异常
![](https://i-blog.csdnimg.cn/blog_migrate/9b5726c05854c99b5449cfc3a374da00.png)
3.3、自定义设置回滚异常
实验5:rollbackFor和rollbackForClassName回滚的异常
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();
}
![](https://i-blog.csdnimg.cn/blog_migrate/2a49499362b990ee0507a93306628120.png)
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();
}
![](https://i-blog.csdnimg.cn/blog_migrate/b16649d575b803666b05c2c9fdd861bb.png)
3.5、事务的传播特性propagation
什么是事务的传播行为:
当事务方法(XxxService())被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为。
事务的传播特性,有以下几种类型:(常用的就前两种,所以下面进行这两种的测试)required(默认的)
![](https://i-blog.csdnimg.cn/blog_migrate/4939fbb27b7ec67617277ec9ec6c5e94.png)
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() {
![](https://i-blog.csdnimg.cn/blog_migrate/61dbf0b601b2b40ffd160c94ef1105b6.png)
实验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()
![](https://i-blog.csdnimg.cn/blog_migrate/d66b08340f9636f22bf086001f1612c0.png)
实验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()
![](https://i-blog.csdnimg.cn/blog_migrate/f4165f6b972ba4bc5ab8095138968c6d.png)
实验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()
![](https://i-blog.csdnimg.cn/blog_migrate/527ceb327ed7ac5b134973cc52a945a7.png)
实验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()
![](https://i-blog.csdnimg.cn/blog_migrate/01a7dfdef463bad8114cace67b546df9.png)
4、xml配置式事务声明
去掉。所有@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不是这个值,这里就一定要加上对应的值了。
5、Spring整合Web
5.1在web工程中添加Spring的jar包。
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(事务管理)
Spring的web整合包
spring-web-4.0.0.RELEASE.jar
测试包
spring-test-4.0.0.RELEASE.jar
整合Spring和Web容器分两个步骤:
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);