Spring之事务管理

举报
浩泽学编程 发表于 2024/01/16 13:27:22 2024/01/16
【摘要】 文章目录前言一、事务及其参数含义1.事务的四个特性2.事务的传播行为(propagation)3.事务隔离性4.事务的隔离级别(ioslation)5.timeout(超时)6.readOnly(是否只读)7.rollbackFor(回滚)8.noRollbackFor(不回滚)二、事务管理1.事务管理的两种形式:2.注解实现声明式事务管理3.xml实现声明式事务管理4.完全注解开发总结前言...



前言

事务是数据库操作最基本单位,要么都成功,要么都失败。


一、事务及其参数含义

1.事务的四个特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性。

2.事务的传播行为(propagation)

Spring定义了7种传播行为:

传播属性 描述
REQUIRED 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW 当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED 当前方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行



这里只图解介绍一个,其他类推

3.事务隔离性

  • 脏读:一个未提交事务读取到另一个未提交事务的数据
    例:事务A读取到事务B修改后的数据,但是读取后事务B回滚了,此时A读取的是修改后的数据,但是修改撤销了。
  • 不可重复读:一个未提交的事务读取到另一个提交事务修改数据
    例:事务A和事务B读取同一个数据,但是事务B在读取后进行修改,然后提交,提交后事务A又读取这个数据,此时读取的是修改后的,跟上次读取的不一样。
  • 幻读(虚读):一个未提交的事务读取到另一个提交事务添加数据

4.事务的隔离级别(ioslation)

5.timeout(超时)

事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。

6.readOnly(是否只读)

读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。

7.rollbackFor(回滚)

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

8.noRollbackFor(不回滚)

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

二、事务管理

Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。

1.事务管理的两种形式:

  • 编程式事务管理
    例:
        try{
            //开启事务

            //进行业务操作
            userDao.reduceMoney();
            //模拟异常
            int i=10/0;
            userDao.addMoney();
            //没出现异常,事务提交
        }catch (Exception e){
            //异常,事务回滚
        }
  • 声明式事务管理(AOP原理)
    例:
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
    @Autowired
    private UserDao userDao;
    public void accountMoney(){
        userDao.reduceMoney();
        int i= 1 / 0;
        userDao.addMoney();
    }
}

2.注解实现声明式事务管理

就是上述声明式管理的例子,这里补充一下全部代码:

================userDao====================
package com.dragon.shiwu.dao;

public interface UserDao {
    public void addMoney();
    public void reduceMoney();
}
==============userDaoImpl===================
package com.dragon.shiwu.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addMoney() {
        String sql="update t_account set money=money + ? where username = ?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void reduceMoney() {
        String sql="update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }
}
==============userService============================
package com.dragon.shiwu.service;

import com.dragon.shiwu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
    @Autowired
    private UserDao userDao;
    public void accountMoney(){
        userDao.reduceMoney();
        int i= 1 / 0;
        userDao.addMoney();
    }
}
============Spring配置文件===========================(注意这里引入了tx命名空间和)
<?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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${pro.driverClass}"></property>
                <property name="url" value="${pro.url}"></property>
                <property name="username" value="${pro.username}"></property>
                <property name="password" value="${pro.password}"></property>
        </bean>
<!--创建JdbcTemplate对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
                <property name="dataSource" ref="dataSource"></property>
        </bean>
        <context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
<!--创建事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"></property>
        </bean>

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

运行前:

运行后:


3.xml实现声明式事务管理

Spring配置文件:

<?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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                                 http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${pro.driverClass}"></property>
        <property name="url" value="${pro.url}"></property>
        <property name="username" value="${pro.username}"></property>
        <property name="password" value="${pro.password}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    开启组件扫描-->
    <context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
    <!--配置事务通知-->
    <tx:advice id="txadvice">
        <tx:attributes>
            <!--配置事务参数-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--    配置切入点和切面-->
    <aop:config>
<!--        配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/>
<!--        配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

4.完全注解开发

TxConfig类:

package com.dragon.shiwu.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration//配置类
@ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

}

测试类:

package com.dragon.shiwu.test;

import com.dragon.shiwu.config.TxConfig;
import com.dragon.shiwu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class test2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService",UserService.class);
        userService.accountMoney();
    }
}


总结

以上就是Spring事务管理的讲解。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。