• spring中的声明式事务


    事务概念

    事务在项目开发过程主要是处理数据的一致性问题!!
    事务是数据库在操作业务逻辑上的一组操作,要么都成功,如果有一个失败这一组操作都失败。

    事务四个属性(ACID)

    • 原子性(atomicity)
      事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
    • 一致性(consistency)
      一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
    • 隔离性(isolation)
      可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
    • 持久性(durability)
      事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中

    spring事务传播特性

    事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:

    • propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
    • propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
    • propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
    • propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
    • propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    • propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
    • propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
      propagation_required类似的操作

    Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。

    假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。

    就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!

    事务隔离级别

    事务有特性称为隔离性,设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和幻读。mysql默认隔离级别可重复读

    • 脏读: 对于两个事务 T1, T2, T1读取了已经被T2更新但还没有被提交的字段。之后, 若T2 回滚,
      T1读取的内容就是临时且无效的。(问题一定要解决,读已提交数据 隔离级别解决)
    • 不可重复读: 对于两个事务T1, T2, T1读取了一个字段, 然后T2更新了该字段。之后, T1再次读取同一个字段,值就不同了。(可以接受,可重复读 隔离级别解决)
    • 幻读: 对于两个事务T1, T2, T1从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。之后, 如果 T1再次读取同一个表, 就会多出几行。(可以接受。串行化 隔离级别解决)

    spring中的事务

    jar包:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>spring-study</artifactId>
            <groupId>com.com.lmy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>spring-06-transcation</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.1.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.3.22</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.29</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <!--使用aop时需导入该jar包-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.9.1</version>
            </dependency>
        </dependencies>
    
    </project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    数据库持久层:

    package com.lmy.dao.impl;
    
    import com.lmy.dao.UserDao;
    import org.springframework.jdbc.core.JdbcTemplate;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author : liu ming yong
     * @date : 2022/8/14 上午 10:28
     * @description : 数据库操作实现类
     */
    public class UserDaoImpl implements UserDao {
        private JdbcTemplate jdbcTemplate;
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        @Override
        public List<Map<String, Object>> getUser() {
            List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from tb_user");
            return list;
        }
    
        @Override
        public Integer addUser(Object[] ars) {
            int update = jdbcTemplate.update("insert into tb_user(username,password,phone,created) values (?,?,?,?)",ars);
            return update;
        }
    
        @Override
        public Integer deleteUser(int id) {
            int update = jdbcTemplate.update("delete from tb_user where id=?",new Object[]{id});
            return update;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    业务逻辑层:

    package com.lmy.service.impl;
    
    import com.lmy.dao.UserDao;
    import com.lmy.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author : liu ming yong
     * @date : 2022/8/14 下午 6:42
     * @description : 用户业务逻辑实现类
     */
    @Service
    public class UserServiceImpl implements UserService {
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public List<Map<String, Object>> getUser() {
            List<Map<String, Object>> list = userDao.getUser();
            Integer integer = userDao.addUser(new Object[]{"wangmazi8", "123", "17823594211", new Date()});
            // 在新增后出现任何错误导致删除不成功时,都面临着事务是否要处理问题。若处理,getUser方法就是一个事务,新增会回滚。若不处理就会新增成功删除失败
    //        int i =1/0;
            Integer update = userDao.deleteUser(33);
            return list;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    配置文件:

    <?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/db2?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <bean id="userDao" class="com.lmy.dao.impl.UserDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"/>
        </bean>
    
        <bean id="userService" class="com.lmy.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
        </bean>
    
    </beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    测试类:

    package com.lmy;
    
    import com.lmy.dao.UserDao;
    import com.lmy.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author : liu ming yong
     * @date : 2022/8/14 上午 10:55
     * @description : spring 事务测试类
     */
    public class myTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("jdbc-resources.xml");
            UserService userService = context.getBean("userService", UserService.class);
            List<Map<String, Object>> list = userService.getUser();
            System.out.println(list);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    结果:未进行事务管理时结果为新增数据库成功,删除数据库失败

    声明式事务

    将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
    将事务管理作为横切关注点,通过spring的aop方法模块化。

    aop所需jar包:

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.9.1</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    声明式事务配置:

        <!--配置声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!--结合AOP实现事务织入,配置事务通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!--给哪些方法配置事务(只有配置了事务的方法才会进行事务管理) *表示所有方法-->
            <tx:attributes>
                <tx:method name="*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <!--配置事务切入-->
        <aop:config>
            <aop:pointcut id="aspect" expression="execution(* com.lmy.service.impl.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="aspect"/>
        </aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    声明式事务结果:因逻辑失败导致删除无法成功,则新增被事务回滚,最后新增删除均不成功

    编程式事务

    将事务管理代码嵌到业务方法中来控制事务的提交和回滚

  • 相关阅读:
    安科瑞无线物联网智能电表ADW300指导性技术要求-Susie 周
    OpenCV学习 基础图像操作(十七):泛洪与分水岭算法
    测不准原理
    设计模式-享元模式(Flyweight)
    迄今为止算是汇总了全网高级Java岗位面试题(附答案)建议收藏
    RecyclerView 空白区域点击事件
    「高效程序员的修炼」快速上手Shell编程、执行与定时任务
    工作纪实38-ES分页数据问题
    大数据Hadoop高可用
    【TB作品】MSP430G2553,单片机,口袋板, 烘箱温度控制器
  • 原文地址:https://blog.csdn.net/qq_41863697/article/details/126091120