• Spring-现事务管理


    目录

     事务概念

    搭建事务操作环境

    下面我们先实现一个简单的无事务转账案例

     解决异常办法:加入事务

    下面介绍如何通过 XML 的方式实现声明式事务管理,步骤如下。

    1. 引入 tx 命名空间

    2. 配置事务管理器

    下面介绍如何通过 注解的方式实现声明式事务管理,步骤如下

    @Transactional注解参数

    完全注解


     事务概念

    1、什么事务
     (1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败.
     (2)典型场景:银行转账
            *lucy转账100元给mary
            *lucy少100,mary多100
     2、事务四个特性(ACID)
      (1)原子性:过程中要么都成成功,要么都失败
      (2)一致性:操作之前和操作之后总量是不变的,比如转账之前有一百,转账后两个人前加起来还是一百
      (3)隔离性:在多事务操作时不会产生影响,比如两个人一同操作同一个事物,他们操作之间不会产生影响
      (4)持久性:事务提交会真正发生变化

    搭建事务操作环境

    我们知道mvc是三层架构,界面层、业务逻辑层、数据访问层,在事务操作时我们先只看业务逻辑层(Srevice)、数据访问层(Dao)。

     

     

    下面我们先实现一个简单的无事务转账案例

    创建service,搭建dao,完成对象创建和注入关系。

    1. @Service
    2. public class UserService {
    3. // 注入dao
    4. @Autowired
    5. private UserDao userdao;
    6. public void accountMoney(){
    7. // lucy少100
    8. userdao.reducwMoney();
    9. // 模拟异常
    10. int i = 10/0;
    11. // marry多100
    12. userdao.addMoney();
    13. }
    14. }
    1. public interface UserDao {
    2. // 多钱
    3. public void addMoney();
    4. // 少钱
    5. public void reducwMoney();
    6. }
    1. @Repository
    2. public class UserDaoImpl implements UserDao{
    3. @Autowired
    4. private JdbcTemplate jdbcTemplate;
    5. // 多钱:marry进账100
    6. @Override
    7. public void addMoney() {
    8. String sql = "update t_account set moeny = moeny+? where username=?";
    9. jdbcTemplate.update(sql, 100,"mary");
    10. }
    11. // 少钱,Lucy转账给marry
    12. @Override
    13. public void reducwMoney() {
    14. String sql = "update t_account set moeny=moeny-? where username=?";
    15. jdbcTemplate.update(sql, 100,"lucy");
    16. }
    17. }

    xml配置:(有固定的模板) 

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    8. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    9. ">
    10. <context:component-scan base-package="com.java.spring">context:component-scan>
    11. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    12. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    13. <property name="url" value="jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
    14. <property name="username" value="root"/>
    15. <property name="password" value="123456"/>
    16. bean>
    17. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    18. <property name="dataSource" ref="dataSource">property>
    19. bean>
    20. <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    21. <property name="dataSource" ref="dataSource">property>
    22. bean>
    23. beans>

    测试

    1. public class Test1 {
    2. @Test
    3. public void testAccount(){
    4. ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    5. UserService userService = context.getBean("userService", UserService.class);
    6. userService.accountMoney();
    7. }

    无异常结果

     有异常结果:Lucy转给Mary100,但由于异常Mary没有得到,导致丢失100.

     解决异常办法:加入事务

    Spring 实现声明式事务管理主要有 2 种方式:

    • 基于 XML 方式的声明式事务管理。
    • 通过 Annotation 注解方式的事务管理。
    • 下面介绍如何通过 XML 的方式实现声明式事务管理,步骤如下。

      1. 引入 tx 命名空间

      Spring 提供了一个 tx 命名空间,借助它可以极大地简化 Spring 中的声明式事务的配置。

      想要使用 tx 命名空间,第一步就是要在 XML 配置文件中添加 tx 命名空间的约束。(由于 Spring 提供的声明式事务管理是依赖于 Spring AOP 实现的,因此我们在 XML 配置文件中还应该添加与 aop 命名空间相关的配置。)
      1. "1.0" encoding="UTF-8"?>
      2. <beans xmlns="http://www.springframework.org/schema/beans"
      3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4. xmlns:context="http://www.springframework.org/schema/context"
      5. xmlns:aop="http://www.springframework.org/schema/aop"
      6. xmlns:tx="http://www.springframework.org/schema/tx"
      7. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
      10. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

      2. 配置事务管理器

      接下来,我们就需要借助数据源配置,定义相应的事务管理器实现的 Bean,配置内容如下。

      1. <context:component-scan base-package="com.java.spring">context:component-scan>
      2. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
      3. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
      4. <property name="url" value="jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
      5. <property name="username" value="root"/>
      6. <property name="password" value="123456"/>
      7. bean>
      8. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      9. <property name="dataSource" ref="dataSource">property>
      10. bean>
      11. <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      12. <property name="dataSource" ref="dataSource">property>
      13. bean>
      14. <tx:advice id="txadvice">
      15. <tx:attributes>
      16. <tx:method name="accountMoney" propagation="REQUIRED"/>
      17. tx:attributes>
      18. tx:advice>
      19. <aop:config>
      20. <aop:pointcut id="pt" expression="execution(* com.java.spring.service.UserService.*(..))"/>
      21. <aop:advisor advice-ref="txadvice" pointcut-ref="pt">aop:advisor>
      22. aop:config>
      23. beans>

      添加事务在发生异常二者都既不少钱也不多钱其余的实体类和上面的UserService一样,接口和接口实现类以及测试类也一样。

    • 上面属性标签解释

    • 元素包含多个属性参数,可以为某个或某些指定的方法(name 属性定义的方法)定义事务属性,如下表所示。 

    propagation:事务传播行为
     当一个事务方法被另外一个事务方法调用时候,这个事务方法如何进行

     

     

     T2并不影响T1,如果1掉完方法2出现了问题它并不影响2,2在自己的事务内运行,可以正常提交

    当前A没有事务,当他调用B时,是不在事务中运行的

     当前A有了事务,调用B时,B在A的事务内运行

    ioslation事务隔离级别
    (1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题。

    (2)有三个读问题:脏读、不可重复读、虚(幻)读

    • 脏读:指事务A读取到了事务B更新了但是未提交的数据,然后事务B由于某种错误发生回滚,那么事务A读取到的就是脏数据。

     

     

     事务A读取到60000后,那60000进行操作,但事务B还没有提交就开始回滚,以至于A拿到错数据去操作

    • 不可重复读:指在数据库访问时,一个事务在前后两次相同的访问中却读到了不同的数据内容。

    • 虚度:一个未提交的事务读取到了另一个提交事务添加的数据
    • 虚读和不可重复读的本质是一样的,两者都表现为两次读取的结果不一致。但是不可重复读指的是两次读取同一条记录的值不同,而幻读指的是两次读取的记录数量不同 

    解决办法:通过设置隔离性,解决三种问题

    下面介绍如何通过 注解的方式实现声明式事务管理,步骤如下

    1.在spring配置文件中配置事务管理器,开启事务注解。

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xmlns:tx="http://www.springframework.org/schema/tx"
    7. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    10. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    11. <context:component-scan base-package="com.java.spring">context:component-scan>
    12. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    13. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    14. <property name="url" value="jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
    15. <property name="username" value="root"/>
    16. <property name="password" value="123456"/>
    17. bean>
    18. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    19. <property name="dataSource" ref="dataSource">property>
    20. bean>
    21. <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    22. <property name="dataSource" ref="dataSource">property>
    23. bean>
    24. <tx:annotation-driven transaction-manager="dataSourceTransactionManager">tx:annotation-driven>
    25. beans>

    2.在Service类(或方法上)上面添加事务注解

    • @Transactional这个注解添加到类上面,为这个该方法添加事务。
    • 如果这个注解添加到类上面,整个类里面的所有方法都添加事务
    • 如果整个主角添加到方法上,为这个该方法添加事务
      1. @Service
      2. @Transactional
      3. public class UserService {
      4. // 注入dao
      5. @Autowired
      6. private UserDao userdao;
      7. public void accountMoney(){
      8. // lucy少100
      9. userdao.reducwMoney();
      10. // 模拟异常
      11. int i = 10/0;
      12. // marry多100
      13. userdao.addMoney();
      14. }
      15. }

      其他类和测试类和第一个类一样,注意配置文件名称更改

    • 发生异常,但该类添加了事务注解,所以Lucy不会少。Mary不会多

    @Transactional注解参数

    第一个参数:事务的传播方式(propagation),第二个隔离性(ioslation

    其他参数

     timeout:超时时间
    (1) 事务需要在一定时间内进行提交,如果不提交进行回滚
    (2) 默认值是-1,设置时间以秒单位进行计算
      readonly:是否只读
    (1)读:查询操作,写:添加修改删除操作
    (2)readonly默认值false,表示可以查询,可以添加修改删除操作。
    (3)设置eadonly.值是true,设置成tru之后,只能查询

    rolbaskor:回滚
    (1)设置出现哪些异常进行事务回滚
    noRolbackFor:不回滚
     (1)设置出现哪些异常不进行事务回滚

    完全注解

    1,创建配置类,使用配置类替代xml配置文件

    2、Spring5.0框架自带了通用的日志封装
     (1)Spring5已经移除Log4jConfigListener,官方建议使用Log42

       (2)Spring5框架整合Log4j2
    第一步引入jar包

     第二步创建log4j2.xml配置文件

    @EnableTransactionManagement//开启事务

    1. @Configuration//配置类
    2. @ComponentScan(basePackages = "com.java")//组建扫描
    3. @EnableTransactionManagement//开启事务
    4. public class TxConfig {
    5. // 创建数据库连接池
    6. @Bean
    7. public DruidDataSource getDruidDataSource(){
    8. DruidDataSource dataSource = new DruidDataSource();
    9. dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    10. dataSource.setUrl("jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
    11. dataSource.setUsername("root");
    12. dataSource.setPassword("123456");
    13. return dataSource;
    14. }
    15. // 创建JdbcTempLate对象
    16. // 应为连接池创建时已经生成了dataSource对象所以这里的参数实在连接池中找的对象,而不是我们要传入的参数
    17. @Bean
    18. public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource){
    19. JdbcTemplate jdbcTemplate = new JdbcTemplate();
    20. // 注入datasource
    21. jdbcTemplate.setDataSource(dataSource);
    22. return jdbcTemplate;
    23. }
    24. // 创建事务管理器
    25. @Bean
    26. public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
    27. DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    28. transactionManager.setDataSource((dataSource));
    29. return transactionManager;
    30. }
    31. }

     测试类

    1. public void testAccount2(){
    2. ApplicationContext context = new AnnotationConfigApplicationContext("TxConfig.class");
    3. UserService userService = context.getBean("userService", UserService.class);
    4. userService.accountMoney();
    5. }


    Spring5框架核心容器支持@Nullable注解
      (1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
       (2)注解用在方法上面,方法返回值可以为空
     
       (3)注解使用在方法参数里面,方法
       

     

     

     

  • 相关阅读:
    香橙派 C# IOT .net 引用官方WiringOP库实现控制操作引脚高低电平 代码实例
    22.1 正则表达式-定义正则表达式、正则语法
    Linux 进程信号
    【算子2】spark(四):spark core:trans算子中key-value类型的算子使用说明
    sql:SQL优化知识点记录(十二)
    4.go语言复合类型简述
    LeetCode力扣(剑指offer 36-39)36. 二叉搜索树与双向链表37. 序列化二叉树38. 字符串的排列39. 数组中出现次数超过一半的数字
    WEB ---- ctfshow ---- PHP特性
    k8s与docker关于CPU竞争测试
    Spring AOP
  • 原文地址:https://blog.csdn.net/m0_56223907/article/details/126926343