Spring框架:第八章:声明式事务

简介: Spring框架:第八章:声明式事务

10、声明式事务

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

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

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

11.1、编码方式实现事务:

11.2、声明式事务环境搭建

11.2.1、准备测试数据库

##创建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;

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

导入jar包:

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
druid-1.1.9.jar
mysql-connector-java-5.1.37-bin.jar
spring-aop-4.3.18.RELEASE.jar
spring-beans-4.3.18.RELEASE.jar
spring-context-4.3.18.RELEASE.jar
spring-core-4.3.18.RELEASE.jar
spring-expression-4.3.18.RELEASE.jar
spring-jdbc-4.3.18.RELEASE.jar
spring-orm-4.3.18.RELEASE.jar
spring-test-4.3.18.RELEASE.jar
spring-tx-4.3.18.RELEASE.jar

配置jdbc.properties属性配置文件:

url=jdbc:mysql://localhost:3306/tx
user=root
password=root
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10

配置Spring的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
  <!-- 配置包扫描 -->
  <context:component-scan base-package="com"></context:component-scan>
  <!-- 加载jdbc.properties属性配置文件 -->
  <context:property-placeholder location="classpath:jdbc.properties"/>
  <!-- 配置数据库连接池 -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="username" value="${user}"/>
    <property name="password" value="${password}"/>
    <property name="url" value="${url}"/>
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="initialSize" value="${initialSize}" />
    <property name="maxActive" value="${maxActive}"/>
  </bean>
  <!-- 配置jdbcTemplate工具类 -->
  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
  </bean> 
</beans>

11.3、测试Service的默认事务

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

@Repository
public class BookDao {
  @Autowired
  JdbcTemplate jdbcTemplate;      
  public void updateBook() {
    jdbcTemplate.update("update book set name = '图书表被修改了'");
  }     
}
@Repository
public class UserDao {
  @Autowired
  JdbcTemplate jdbcTemplate;      
  public void updateUser() {
    jdbcTemplate.update("update user set username = '用户表被修改了'");
  }     
}
@Service
public class TransactionService {
  @Autowired
  private UserDao userDao;    
  @Autowired
  private BookDao bookDao;      
  public void multiUpdate() {
    userDao.updateUser();
    bookDao.updateBook();
  } 
}

异常的演示

@Service
public class TransactionService {
  @Autowired
  private UserDao userDao;
  @Autowired
  private BookDao bookDao;
  public void multiUpdate() {
    userDao.updateUser();
    int i = 12 / 0 ;
    bookDao.updateBook();
  }
}

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

事务管理器实现类

由于我们使用的是数据库连接池访问数据库,所以事务管理器使用的是DataSourceTransactionManager。

11.4、使用Spring的注解声明事务管制

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

1、在需要事务的方法上加入注解。

/**
 * @Transactional 表示当前方法有事务
 */
@Transactional
public void multiUpdate() {
  userDao.updateUser();
  int i = 12 / 0 ;
  bookDao.updateBook();
}

2、配置事务管理器驱动

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

3、配置事务注解驱动

<!-- 
  <tx:annotation-driven/> 开启注解的事务驱动 启用代理
    transaction-manager="transactionManager" 配置事务管理器
    如果事务管理器的id值是transactionManager,则事务管理器属性可以省略
 -->
<tx:annotation-driven />

11.5、noRollbackFor和noRollbackForClassName测试不回滚的异常

实验3:noRollbackFor和noRollbackForClassName测试不回滚的异常

  /**
   * @Transactional 表示当前方法有事务<br/>
   *  默认情况下。RuntimeException运行时异常和运行时子异常。都会回滚事务<br/>
   * noRollbackFor=java.lang.ArithmeticException.class 表示算术异常不回滚事务<br/>
   * noRollbackFor= {java.lang.ArithmeticException.class,java.lang.NullPointerException.class}<br/>
   * noRollbackForClassName="java.lang.NullPointerException" 设置哪些类名的异常不回滚事务<br/>
   */
  @Transactional(noRollbackForClassName="java.lang.NullPointerException")
  public void multiUpdate() {
    userDao.updateUser();
//    int i = 12 / 0 ;
    Object object = null;
    System.out.println( object.toString() );
    bookDao.updateBook();
  }

11.6、自定义设置回滚异常

实验5:rollbackFor和rollbackForClassName回滚的异常

/**
 * @throws FileNotFoundException 
 * @Transactional 表示当前方法有事务<br/>
 *  默认情况下。RuntimeException运行时异常和运行时子异常。都会回滚事务<br/>
 * rollbackFor=FileNotFoundException.class 设置当抛出FileNotFoundException异常时,回滚事务<br/>
 * rollbackForClassName="java.io.FileNotFoundException" 设置当抛出FileNotFoundException异常时就会回滚事务<br/>
 */
@Transactional(rollbackForClassName="java.io.FileNotFoundException")
public void multiUpdate() throws FileNotFoundException {
  userDao.updateUser();
  int i = 12 ;
  if (i == 12) {
    throw new FileNotFoundException();
  }
  bookDao.updateBook();
}

11.7、事务的只读属性

实验4:测试readOnly只读属性

/**
 * @throws FileNotFoundException 
 * @Transactional 表示当前方法有事务<br/>
 *  默认情况下。RuntimeException运行时异常和运行时子异常。都会回滚事务<br/>
 * readOnly=false 表示当前方法可以执行读操作。也可以执行写操作(指的是sql语句)。<br/>
 * 修改、添加、删除、是写操作、select查询语句是读操作。<br/>
 * readOnly=true 表示当前方法只能执行查询操作<br/>
 */
@Transactional(readOnly=true)
public void multiUpdate() throws FileNotFoundException {
  userDao.updateUser();
  bookDao.updateBook();
}

只读的方法执行修改语句报错。

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

/**
 * @throws FileNotFoundException 
 * @Transactional 表示当前方法有事务<br/>
 *  默认情况下。RuntimeException运行时异常和运行时子异常。都会回滚事务<br/>
 * timeout=3 表示3秒之后就超时,不允许再执行sql语句
 */
@Transactional(timeout=3)
public void multiUpdate() throws FileNotFoundException {
  userDao.updateUser();
  try {
    Thread.sleep(5000);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  bookDao.updateBook();
}

当执行时间超过指定的秒钟后就会超时:

11.10、事务的传播特性propagation

什么是事务的传播行为:

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

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

事务的传播特性,有以下几种类型:

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

UserService

BookService

TransactionService

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

  @Transactional(propagation = Propagation.REQUIRED)
  public void multlTransaction() {
  @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()

12、xml配置式事务声明

复制原来注解事务管理的工程。去掉里面所有@Transactional的注解。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
  <!-- 配置包扫描 -->
  <context:component-scan base-package="com"></context:component-scan>
  <!-- 加载jdbc.properties属性配置文件 -->
  <context:property-placeholder location="classpath:jdbc.properties"/>
  <!-- 配置数据库连接池 -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="username" value="${user}"/>
    <property name="password" value="${password}"/>
    <property name="url" value="${url}"/>
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="initialSize" value="${initialSize}" />
    <property name="maxActive" value="${maxActive}"/>
  </bean>
  <!-- 配置jdbcTemplate工具类 -->
  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
  </bean>
  <!-- 
    配置事务管理器
   -->
  <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就是方法的匹配规则(方法名)
          精确匹配
       -->
      <tx:method name="updateUser" propagation="REQUIRED"/>
      <!-- 
        给save*方法配置事务属性
          name="save*"  表示给save字符串打头的方法配置事务属性
       -->
      <tx:method name="save*" propagation="REQUIRED"/>
      <tx:method name="update*" propagation="REQUIRES_NEW"/>
      <tx:method name="delete*" propagation="REQUIRED"/>
      <tx:method name="multlTransaction" propagation="REQUIRES_NEW"/>
      <!-- 
        <tx:method name="*"/> 所有的方法
          read-only="true" 剩下的方法都是查询操作。
       -->
      <tx:method name="*" read-only="true"/>
    </tx:attributes>
  </tx:advice>
  <aop:config>
    <!-- 
      aop:advisor 配置通知
     -->
    <aop:advisor advice-ref="tx_advice" 
      pointcut="execution(public * com.service..*Service*.*(..))"/>
  </aop:config>
</beans>
相关文章
|
1月前
|
XML 安全 Java
|
9天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
5天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
30 13
|
30天前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
45 2
Spring高手之路26——全方位掌握事务监听器
|
17天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
34 5
|
27天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
62 8
|
Java Spring
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
137 0
|
缓存 监控 Java
Spring框架之AOP(面向切面编程)
Spring框架之AOP(面向切面编程)
64 0
|
6月前
|
分布式计算 Java MaxCompute
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
|
7月前
|
设计模式 SQL Java
Spring框架第四章(AOP概念及相关术语)
Spring框架第四章(AOP概念及相关术语)