spring配置事务

0. 前提

如果你要了解事务,请你先学会这些知识

  1. spring (IOC和AOP,AOP是重点)
  2. spring使用JDBCTemplate (这个很简单)
  3. 会配置一个数据源 (DBCP、C3p0或者Druid都行)
  4. 数据库至少会一种(Mysql、Oracle)

1. 什么是事务

对于最简单的理解就是,一个不可分割的事情,例如转账的时候,
A 转给 B 100块,那么就是A先减去100,然后B加上100。这个是一个不可分割的事情。就是一个简单的事务
实际上就是一组 sql一起执行

2. 事务的基本原则(AICD 原则)

原子性:
一致性:
隔离性:
持久性:

3. 事务隔离级别

事务的隔离级别有四种

  1. read uncommit (读未提交)
  2. read commit (读已提交)
  3. repeatable read (可重复读)
  4. serialzale (序列化)就是锁表
    在事务的并发过程中有可能出现下面的问题,根据业务来选择使用哪种隔离级别
    脏读:
    幻读:
    不可重复读:
    第一类丢失更新:
    第二类丢失更新:
数据库默认的隔离级别

例如:oracle、sqlserver默认使用的 read commited (读已提交)
mysql 默认使用的 repeatable read (可重复读)

Spring怎么配置的事务?

有几种配置,我这里就简单的说三种吧

  1. 使用TransactionTemplate实现事务
    这种方法只需要配置事务管理器(DataSourceTransactionManager)和模板(TransactionTemplate)
<!--    配置事务-->
<!--    事务管理器-->
    <bean id="dataTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    管理事务的模板  -->
    <bean id="dataTxTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="dataTxManager"/>
    </bean>

在使用事务的时候就要用 transactionTemplateexecute 来执行事务。。

@Component
public class UserService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private TransactionTemplate transactionTemplate;


    public void transfer(String from,String to,int mola){
        transactionTemplate.execute((transactionStatus)->{
            userDao.out(from,mola);
            int num = 10;
            if (num==10){
                throw new RuntimeException("出错了");
            }
            userDao.in(to,mola);
            return null;
        });

    }
}

这种方法的缺点就是对代码的侵入性比较强。。。

  1. 使用AOP来实现事务
    第二种写法就是用Aop动态代理来实现事务,这种写法是现在最常用的方法

具体的xml配置如下

<!--    事务管理器-->
    <bean id="dataTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<tx:advice id="txAdvice" transaction-manager="dataTxManager">
        <tx:attributes>
            <tx:method name="get*" propagation="NOT_SUPPORTED" />
            <tx:method name="in" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="transfer" propagation="REQUIRED" rollback-for="Exception" />
            <!-- ... -->
        </tx:attributes>
    </tx:advice>

    <!--  配置参与事务的类 -->
    <aop:config>
        <aop:pointcut id="transcationPointcut" expression="execution(public void com.liliya.service.UserService.*(..))"/>
        <aop:advisor pointcut-ref="transcationPointcut" advice-ref="txAdvice" />
    </aop:config>
  1. 使用注解的方式来实现事务
    使用注解的好处就是没有配置文件了。。使用事务的时候就在类上添加一个
    @Transactional 就好了,,
    当然,, 如果某个方法上不想使用事务的话,那就用 @Transactional(propagation = Propagation.NOT_SUPPORTED)这个注解放到那个方法上。。。qwq

AppConfig.java

@ComponentScan("com.liliya")
@EnableAspectJAutoProxy
@EnableTransactionManagement
@Configuration
public class AppConfig {

    @Bean
    public TransactionManager getTransactionManager() {
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(dataSource());
        return manager;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/txdemo?serverTimezone=UTC");
        dataSource.setUser("root");
        dataSource.setPassword("admin");
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");

        return dataSource;
    }
}

例如我是这么写的

//转账
@Component
@Transactional
public class UserService {
    @Autowired
    private UserDao userDao;

    //转账
    public void transfer(String from,String to,int mola){
            userDao.out(from,mola);
            int num = 10;
            //故意出一个错误,导致转账失败
            if (num==10){
                throw new RuntimeException("出错了");
            }
            userDao.in(to,mola);

    }
}

测试类就要注解的来写了

    @Test
    public void tss(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService bean = context.getBean(UserService.class);
        bean.transfer("刘国威","屎魔翔",100);
        System.out.println("跑完了!!!");
    }

在这里插入图片描述

其他补充

  1. 用到了依赖有这些
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.4</version>
    </dependency>
  1. 使用事务管理器 DataSourceTransactionManager 是需要配置数据源 dataSource
    每种数据源的配置都不同,所以我这里没有贴出来。。
    而且这个百度一大堆
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值