ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring08:Spring中事务管理

2021-05-14 13:03:08  阅读:104  来源: 互联网

标签:事务管理 事务 deleteById Spring08 int Spring public id


1、事务回顾

  • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
  • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。

事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。

事务四个属性ACID

  1. 原子性(atomicity)

    • 事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
  2. 一致性(consistency)

    • 一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
  3. 隔离性(isolation)

    • 可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
  4. 持久性(durability)

    • 事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中

2、事务控制概述

下面主要讲解Spring的事务控制,如何使用Spring来对程序进行事务控

  • Spring的事务控制是属于Spring Dao模块的。

一般地,我们事务控制都是在service层做的。。为什么是在service层而不是在dao层呢??有没有这样的疑问...

service层是业务逻辑层,service的方法一旦执行成功,那么说明该功能没有出错

一个service方法可能要调用dao层的多个方法...如果在dao层做事务控制的话,一个dao方法出错了,仅仅把事务回滚到当前dao的功能,这样是不合适的[因为我们的业务由多个dao方法组成]。如果没有出错,调用完dao方法就commit了事务,这也是不合适的[导致太多的commit操作]。

事务控制分为两种:

  • 编程式事务控制

  • 声明式事务控制

3.1、编程式事务控制

自己手动控制事务,就叫做编程式事务控制。

  • Jdbc代码:Conn.setAutoCommite(false); // 设置手动控制事务

  • Hibernate代码:Session.beginTransaction(); // 开启一个事务

  • 特点:细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制(比较灵活,但开发起来比较繁琐:每次都要开启、提交、回滚)

3.2、声明式事务控制

Spring提供对事务的控制管理就叫做声明式事务控制

Spring提供了对事务控制的实现。

  • 如果用户想要使用Spring的事务控制,只需要配置就行了

  • 当不用Spring事务的时候,直接移除就行了。

  • 特点:Spring的事务控制是基于Spring AOP实现的。因此它的耦合度是非常低的。【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】(因为aop拦截的是方法。)

Spring给我们提供了事务的管理器类,事务管理器类又分为两种,因为JDBC的事务和Hibernate的事务是不一样的。

Spring声明式事务管理器类:

  • Jdbc技术:DataSourceTransactionManager

  • Hibernate技术:HibernateTransactionManager

3.3、声明式事务控制使用

1、引入相应pom依赖

<!-- aspectj AOP -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

<!-- spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.5</version>
</dependency>

2、创建实体类

public class User {
    private Integer id;
    private String name;
    private String pwd;
    
	//各种setter,getter,toString
}

3、创建mapper接口

public interface UserMapper {

    @Delete("delete from user where id = #{id}")
    int deleteById(@Param("id") int id);

}

4、创建mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <settings>
        <!-- 内置日志 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--  设置别名  -->
    <typeAliases>
        <package name="org.com.pojo"/>
    </typeAliases>

</configuration>

5、创建UserService接口及其实现类

public interface UserService {

    int deleteById(int id);

}
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    
    @Override
    public int deleteById(int id) {
        return userMapper.deleteById(id);
    }
}

6、配置spring配置文件,整合mybatis

<?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
	   http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd
        ">
    <!-- 扫描注解 -->
    <context:component-scan base-package="org.com.service"/>

    <!--
    读取数据库配置文件
    system-properties-mode="NEVER" :防止${xxx}读取环境变量
    -->
    <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>

    <!-- 创建sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!-- 注册mapper映射器并放入Spring中 -->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="org.com.mapper.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>


    <!-- 配置声明式事务 -->
    <!--1.配置事务的管理器类:JDBC-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--引用数据库连接池-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--2.配置如何管理事务-->
    <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
        <!--配置事务的属性-->
        <tx:attributes>
            <!--所有的方法,并不是只读-->
            <tx:method name="*" read-only="false"/>
        </tx:attributes>
    </tx:advice>

    <!--3.配置拦截哪些方法+事务的属性-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* org.com.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>



</beans>

7、数据库配置(db.properties)

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username = root
password = 123456

8、测试

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        userService.deleteById(4);
    }
}

测试前数据库

测试后数据库

9、我们把UserServiceImpl中deleteById方法修改一下测试事务

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    
    @Override
    public int deleteById(int id) {
        userMapper.deleteById(2);
        // 这里会报错,我们配置了事务,所以这个方法中的两个删除操作都不会成功
        int temp = 1 / 0;
        return userMapper.deleteById(id);
    }
}

10、再次测试

@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
    UserService userService = context.getBean("userServiceImpl", UserService.class);
    userService.deleteById(3);
}
}

使用注解的方法实现事务控制

上面这是用xml的方式实现的,下面我们用注解实现

1、第一步和XML的是一样的,必须配置事务管理器类

<!-- 配置声明式事务 -->
<!-- 1.配置事务的管理器类:JDBC -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 引用数据库连接池 -->
    <property name="dataSource" ref="dataSource"/>
</bean>

2、开启以注解的方式来实现事务控制

<!-- 2.开启以注解的方式来实现事务控制 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

3、想要控制哪个方法事务,在其前面添加@Transactional这个注解就行了!如果想要控制整个类的事务,那么在类上面添加就行了。

// @Transactional
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    @Override
    public int deleteById(int id) {
        userMapper.deleteById(2);
        // 这里会报错,我们配置了事务,所以这个方法中的两个删除操作都不会成功
        int temp = 1 / 0;
        return userMapper.deleteById(id);
    }
}

4、测试,结果正常(出现异常,事务回滚,没有数据被修改)

3、事务属性

其实我们在XML配置管理器类如何管理事务,就是在指定事务的属性!我们来看一下事务的属性有什么:

3.1、事务传播行为

看了上面的事务属性,没有接触过的属性其实就这么一个:propagation = Propagation.REQUIRED事务的传播行为。

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

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

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

公众号

标签:事务管理,事务,deleteById,Spring08,int,Spring,public,id
来源: https://www.cnblogs.com/javaconner/p/14768109.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有