关于事务的概念以及分析

事务

什么是事务?

  • 事务是数据库操作最基本单元,逻辑上一组操作 ,要么都成功,如果有一个失败那么所有操作都会失败

  • 典型场景:银行转账

Lucy转账100给 Mary

Lucy少100,Mary多100

事务的四大特性--ACID

  • 原子性

  • 一致性

  • 隔离性

  • 持久性

环境的搭建

接下来我们使用最为传统的转账的情况下进行搭建

1.通过在数据库进行添加两条表记录

INSERT INTO t_user(username, money) VALUES('Lucy', 1000),('Mary', 1000);

2.创建上图的service,dao,以及dao的实现类daoImpl,创建完成之后进行在service中注入dao,在dao中注入JdbcTemplate,在JdbcTemplate中注入dataSource

<!--开启组件扫描-->
<context:component-scan base-package="com.xuan"/>
​
<!--数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql:///guigu_bookdb" />
    <property name="username" value="root" />
    <property name="password" value="root" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
​
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入dataSource-->
    <property name="dataSource" ref="dataSource"/>
</bean>

3.进行创建一个测试类进行测试

@Test
public void t1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    UserService userService = context.getBean("userService", UserService.class);
    userService.accountTest();
}

上面就是基本的环境搭建

而我们既然运用转账的这个例子那么就是要去引出问题,加入转账的时候一方的网络出现问题,此时代码就会出现异常,此时就需要去运用事务来进行解决。

出现异常的代码如下 :

public void accountTest(){
    // Lucy 给 Mary 转 100
    userDao.reduceMoney();
    
    // 模拟网络异常
    int i = 1/0;
​
    // Mary 收到 Lucy 的 100
    userDao.addMoney();
}

初步的解决方案;

而这种解决方案是不是看起来非常的繁琐呢,其实接下来我们要学习的关于事务的操作才是本文的重点,请继续往下面看。

Spring事务管理介绍

在javaEE的三层结构之中,我们关于事务的操作一般看成一种处理问题的解决方案,这个一般都写在Service层(业务逻辑层);

在spring中的事务管理操作,一般的话会有两种方式:

  • 编程式的事务管理,就是上面我说的比较复杂的方式进行事务管理

  • 声明式事务管理(重点)

声明式事务管理:

  • 基于注解的方式

  • 基于配置文件的方式(XML)

这里进行补充一下,在Spring中实现声明式事务管理的底层使用了AOP原理

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

声明式事务管理(注解)

  1. 在Spring配置文件中配置事务管理器;

    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
  2. 在配置文件中开启事务注解;

    引入名称空间:

    开启事务注解:

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  3. 在Service类上面(或者Service类里面的方法上)添加事务注解;

    • @Transactional,这个注解可以添加到类上面,也可以添加到方法上面;

    • 如果把这个注解添加类上面,则这个类里面所有的方法都会被添加事务;

    • 如果把这个注解添加方法上面,则这个方法会被添加事务;

    @Service
    @Transactional  // 使用声明式注解
    public class UserService {}

声明式事务管理参数配置

在Service类上面添加注解@Transactional,在这个注解里面可以配置相关的参数。

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

REQUIRED:

REQUIRED_NEW:

SUPPORTS:

@Transactional(propagation = Propagation.REQUIRED) 
1

2. ioslation: 事务隔离级别

事务中有一个特性,这个特性交隔离级别,多事务操作之间不会产生影响。如果不考虑事务的隔离性,则会产生很多的问题。主要有三大问题:

  • 脏读:一个未提交事务读取到另一个未提交事务的数据,通常都与事务的回滚有关;

  • 不可重复读:一个未提交事务读取到另一提交事务修改的数据;

  • 幻读;一个未提交事务读取到另一提交事务添加的数据;

通过设置事务的隔离级别可以解决以上的问题。

脏读不可重复读幻读
READ UNCOMMITTED(读未提交)
READ COMMITTED(读已提交)
REPEATABLE READ(可重复读)
SERIALIABLE(串行化)
@Transactional(isolation = Isolation.READ_COMMITTED) 
1

3. timeout: 超时时间

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

5. readOnly: 是否只读

读通常对应于数据库的查询操作,写对应于数据库的添加、修改、删除操作。readOnly 默认值 false,表示可以进行CRUD操作,如果设置 readOnly 值为 true,则只能进行查询。

6. rollbackFor: 回滚

设置当程序出现哪些异常时,进行事务的回滚。

7. noRollbackFor: 不回滚

设置当程序出现哪些异常时,不进行事务的回滚。

在这里XML声明式事务管理我就不写了,这个作为一个了解即可,大部分情况下我们都是采用注解的方式来进行实现声明式事务管理

完全注解实现声明式事务管理

​
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("com.xuan") // 组件扫描
@EnableTransactionManagement // 开启事务
public class TxConfig {
    // 创建数据库连接池
    @Bean  // 这个注解对应于配置文件中的bean标签
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///guigu_bookdb");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    /**
     * 创建JdbcTemplate对象
     * @param dataSource DataSource源,巧妙思想:直接让Spring到ioc容器中去寻找对应的类型。
     * @return JdbcTemplate对象。
     */
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        // 到ioc容器中根据类型找到dataSource进行注入
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
​
    // 创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

以上就是关于事务的一些知识了,谢谢你的观看了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值