Spring的事务管理

事务的定义

事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败

事务的特性

  • 原子性:事务不可分割
  • 一致性:事务执行前后数据完整性保持一致
  • 隔离性:一个事务的执行不应该受到其他事务的干扰
  • 持久性:一旦事务结束,数据就持久化到数据库
如果不考虑隔离性可能引发的安全性问题
  • 读问题
    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
    • 虚读、幻读:一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致
  • 写问题
    • 丢失更新
解决读问题

设置事务的隔离级别

  • Read uncommitted:未提交读,任何读问题都解决不了
  • Read committed:已提交读,解决脏读,但是不可重复读和虚读都有可能发生(Oracle)
  • Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生(mysql)
  • Serializable:解决所有读问题

Spring的事务管理的API

PlatformTransactionManager:平台事务管理器

平台事务管理器:接口,是Spring用于管理事务真正的对象

  • DataSourceTransactionManager:底层使用JDBC管理事务
  • HibernateTransactionManager:底层使用Hibernate管理事务
TransactionDefinition:事务定义信息

事务定义:用于定义事务的相关信息,隔离级别、超时信息、传播行为、是否只读

TransactionStatus:事务的状态

事务状态:用于记录在事务管理过程中,事务的状态的对象

事务管理的API的关系

Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中

事务的传播行为

事务的传播行为用来解决业务层方法相互调用的问题
Spring中提供了七种事务传播行为,大体分为三类

  • 保证同一个事务中
    • PROPAGATION_REQUIRED 支持当前事务,如果不存在就新建一个(默认值)
    • PROPAGATION_SUPPORTS 支持当前事务,如果不存在就不使用事务
    • PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
  • 保证没有在同一个事务中
    • PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
    • PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
    • PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
  • 如果当前事务存在,则嵌套事务执行
    PROPAGATION_NESTED

Spring的事务管理

搭建转账环境
依赖添加
  1. Spring的四个核心依赖
  2. Spring的四个AOP依赖
  3. mysql数据库的jar包
  4. Spring-JDBC的jar包
  5. mybatis自身jar包和Spring支持mybatis框架的jar包
  6. c3p0的两个jar包
  7. Spring的测试包
  8. Junit的单元测试包
  9. get和set方法的辅助jar包
 <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.aopalliance/com.springsource.org.aopalliance -->
        <dependency>
            <groupId>org.aopalliance</groupId>
            <artifactId>com.springsource.org.aopalliance</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>
        
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--spring整合mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>mchange-commons-java</artifactId>
            <version>0.2.11</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
创建数据库,账号,姓名,金钱
创建实体类
配置文件
  1. mybatis-config.xml

    • 配置打印sql语句日志
    • 配置别名
    <?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>
            <typeAlias type="com.aop.pojo.User" alias="User"></typeAlias>
        </typeAliases>
    </configuration>
    
  2. application-context.xml

    • 配置组件扫描
    • AOP注解开发
    • c3p0注入bean管理
    • mybatis注入bean管理
    <?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: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-3.2.xsd
    						http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-4.0.xsd
    						http://www.springframework.org/schema/aop
    						http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    
        <context:component-scan base-package="com.aop"></context:component-scan>
        <!--开启AOP的注解开发-->
        <aop:aspectj-autoproxy/>
        
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test7?serverTimezone=Asia/Shanghai&amp;characterEncoding=UTF-8&amp;useSSL=false"></property>
            <property name="user" value="root"></property>
            <property name="password" value="cqrjxk39"></property>
        </bean>
    
        <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            <property name="mapperLocations" value="classpath:com/aop/dao/*.xml"></property>
            <property name="configLocation" value="classpath:mybatis-cfg.xml"></property>
        </bean>
    
        <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.aop.dao"></property>
            <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
        </bean>
    
    </beans>
    
    
使用mybatis框架编写dao层,一个修改功能,一个查询功能
service层编写

为测试类提供转账业务

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    public void deal(String fromkid, double fromMoney, String tokid, double toMoney) {
        User fromUser = new User();
        User toUser = new User();
        fromUser.setKid(fromkid);
        fromUser.setMoney(fromMoney);
        toUser.setKid(tokid);
        toUser.setMoney(toMoney);
        userDao.update(fromUser);
        userDao.update(toUser);
    }
}
测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context.xml")
public class TestDemo1 {
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        System.out.println("转账前");
        findMoney();
        userService.deal("11111",-100,"22222",100);
        System.out.println("转账后");
        findMoney();
    }

    public void findMoney(){
        User fromUser = userDao.find("11111");
        User toUser = userDao.find("22222");
        System.out.println("转账人:"+fromUser+"\t收账人:"+toUser);
    }
}
产生的问题

如果在转账的过程中代码出现了异常情况,就会造成金钱丢失

Spring的事务管理

编程式事务
第一步:配置平台事务管理器
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
第二步:配置事务管理的模板
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>
第三步:注入事务模板到业务层
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

	//注入事务模板
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void deal(final String fromkid,  final String tokid, final double Money) {
        
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                User fromUser = new User();
                User toUser = new User();
                fromUser.setKid(fromkid);
                fromUser.setMoney(-Money);
                toUser.setKid(tokid);
                toUser.setMoney(Money);
                userDao.update(fromUser);
                int i = 1/0;
                userDao.update(toUser);
            }
        });
    }
}
声明式事务管理

通过AOP进行声明式事务管理

XML方式的声明式事务管理

第一步:引入AOP的开发环境(上面已引入AOP的jar包),引入tx的jar包

 		<!--https://mvnrepository.com/artifact/org.springframework/spring-tx-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

第二步:配置事务管理器
第三步:配置事务的增强规则
(在这里还可以配只读read-only,配超时timeout,timeout的值为-1表示没有过期时间)

	<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"></tx:method>
            <tx:method name="update*" propagation="REQUIRED"></tx:method>
            <tx:method name="delete*" propagation="REQUIRED"></tx:method>
            <tx:method name="find*" read-only="true"></tx:method>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

第四步:配置切点

	<aop:config>
        <aop:pointcut id="pointCut1" expression="execution(* com.aop.service.impl.UserServiceImpl.deal(..))"></aop:pointcut>
        <!--advisor是一个切入点和一个通知的组合,aspect是多个切入点和多个通知的组合-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut1"></aop:advisor>
    </aop:config>

第五步:测试(Spring的AOP一章有)

注解方式的声明事务管理

第一步:引入AOP开发环境
第二步:配置事务管理器
第三步:开启注解事务

<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

第四步:在业务层的类上添加注解@Transactional
该注解有两个重要的属性,isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,可以设置隔离级别和传播行为。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值