spring事务入门级理解

    科技2024-10-03  23

    文章目录

    一、事务概念二、spring事务三、事务操作(注解实现声明式事务管理)3.1、在spring配置文件中配置事务管理器3.2、在spring配置文件中开启事务注解3.3、在service类上面(或者service类里面方法上)添加事务注解 四、声明式事务管理参数配置4.1、propagation:事务传播行为4.2、ioslation:事务隔离级别4.3、timeout:超时时间4.4、readOnly:是否只读4.5、rollbackFor:回滚4.6、noRollbackFor:不回滚

    一、事务概念

    1、什么是事务

    事务是数据库操作最基本的单元,逻辑上一组操作,要么都成功,如果有一个失败,则所有操作都失败

    经典场景:银行转账

    2、事物的四个特性(ACID)

    原子性、一致性、隔离性、持久性

    3、引出事务操作

    (1)数据库建表account,并插入数据

    pom依赖

    <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.0.RELEASE</version> </dependency> </dependencies>

    核心配置文件application.xml

    <?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: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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 开启组件扫描--> <!-- 2、扫描上层--> <context:component-scan base-package="com.lu"></context:component-scan> <!-- 数据库连接池。 destroy-method="close"作用是当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用. xml中:&要用 &amp; 转义--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/spring-crud?userSSL=true&amp; useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSourceDefault--> <property name="dataSource" ref="dataSource"></property> </bean> </beans>

    (2)创建service,dao完成对象创建和注入关系

    UserDao类

    public interface UserDao { void addMoney(); void reduceMoney(); }

    UserDaoImpl类

    @Repository public class UserDaoImpl implements UserDao{ @Autowired private JdbcTemplate jdbcTemplate; public void addMoney() { String sql = "update account set money = money-? where username=?"; jdbcTemplate.batchUpdate(sql,"100","lucy"); } public void reduceMoney() { String sql = "update account set money = money+? where username=?"; jdbcTemplate.batchUpdate(sql,"100","tom"); } }

    UserService类

    @Service public class UserService { //注入dao @Autowired private UserDao userDao; //转账方法 public void accountMoney(){ //lucy少100 userDao.reduceMoney(); //tom多100 userDao.addMoney(); } }

    测试类TestAccount

    public class TestAccount { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); UserService userService = context.getBean("userService",UserService.class); userService.accountMoney(); } }

    3、正常执行上边程序,是没问题的。但是,如果在步骤中间,有异常,就可能导致一个成功、一个失败的问题,进而导致钱数错误。

    //转账方法 public void accountMoney(){ //lucy少100 userDao.reduceMoney(); //模拟异常 int i= 10/0; //tom多100 userDao.addMoney(); }

    4、如何解决上边的问题?

    使用事务进行解决

    事务操作的过程

    二、spring事务

    1、事务添加到JavaEE三层架构里面的Service层(业务逻辑层)

    2、spring中有两种事务管理方式

    编程式事务管理(如上图,4步)

    声明式事务管理(常用)

    3、声明式事务管理

    基于注解方式(常用)基于xml配置文件方式

    4、在spring进行声明式事务管理,底层使用AOP

    5、spring事务管理API

    (1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

    三、事务操作(注解实现声明式事务管理)

    3.1、在spring配置文件中配置事务管理器

    <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源。ref后跟的式数据源--> <property name="dataSource" ref="dataSource"></property> </bean>

    3.2、在spring配置文件中开启事务注解

    在spring配置文件中引入名称空间tx

    开启事务注解 <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

    3.3、在service类上面(或者service类里面方法上)添加事务注解

    @Transactional,这个注解可以添加类上面,也可以添加方法上面。

    添加到类上面,这个类里面所有方法都添加事务。

    添加到方法上面,只是为这个方法添加事务。

    四、声明式事务管理参数配置

    在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数。

    4.1、propagation:事务传播行为

    使用方法:就是在Transactional注解后边的括号内添加propagation = xxx 例如: @Transactional(propagation = Propagation.REQUIRED)

    事务传播行为一般是:多事务方法之间的调用,这个过程中事务时如何进行管理的

    图片来自尚硅谷王泽老师B站视频

    事务的传播行为指方法之间事务的传播,比如方法A调用了方法B: 有7种,required 、required_new常用:

    REQUIRED Spring默认的传播机制,如果A有事务就使用当前事务, 如果A没有事务, 就创建一个新事务。REQUIRES_NEW 不管A有没有事务都创建一个新事务。NEVER 如果A有事务就抛异常, 如果A没有事务, 就以非事务执行。

    4.2、ioslation:事务隔离级别

    使用方法:就是在Transactional注解后边的括号内添加,如下。如果有多种,逗号隔开。 @Transactional(isolation = Isolation.REPEATABLE_READ)

    并发下事务会产生的问题

    举个例子,事务A和事务B操纵的是同一个资源,事务A有若干个子事务,事务B也有若干个子事务,事务A和事务B在高并发的情况下,会出现各种各样的问题。

    脏读、不可重复读、幻读

    (1)脏读(Dirty read) 脏读发生在一个事务读取了被另一个事务改写但尚未提交的数据时。

    (2)不可重复读(Nonrepeatable read) 不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据。

    (不可重复读重点在修改)

    (3)幻读(Phantom reads) 幻读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入或者删除了一些记录时,幻读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有或少了的额外记录。 (幻读重点在新增或删除) 参考的blog:https://www.cnblogs.com/mseddl/p/11577846.html

    解决:通过设置事务隔离级别,解决读的问题

    隔离级别含义Read Uncommitted读未提交:可能导致脏读、幻读或不可重复读。Read Committed读已提交:可防止脏读,但幻读和不可重复读仍可能发生。Repeated Read可重复读:可防止脏读和不可重复读,但幻读仍可能发生。Serializable串行化:完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。

    4.3、timeout:超时时间

    事务需要在一定时间内进行提交,如果不提交,进行回滚默认值是-1,设置时间以秒单位进行计算设置格式:@Transactional(timeout = -1)

    4.4、readOnly:是否只读

    readOnly默认值是false,表示可以查询,可以添加、修改和删除操作可以设置readOnly值是true,设置之后,只能查询设置格式:@Transactional(readOnly = false)

    4.5、rollbackFor:回滚

    @Transactional的rollbackFor用于指定能够触发事务回滚的异常类型,可以指定多个,用逗号分隔。rollbackFor默认值为UncheckedException,包括了RuntimeException和Error.当我们直接使用@Transactional不指定rollbackFor时,Exception及其子类都不会触发回滚。设置格式:@Transactional(rollbackOn = Exception.class)

    4.6、noRollbackFor:不回滚

    设置出现哪些异常不进行事务回滚

    练习代码: 链接:https://pan.baidu.com/s/1jOYuR-sfeT6DFhLWXqJOpg 提取码:vx8x

    Processed: 0.009, SQL: 8