spring控制事务:声明式事务(注解)

声明式事务(注解)

spring声明事务的方式,使用注解的方式

@Transactional

⚫ 名称:@Transactional
⚫ 类型:方法注解,类注解,接口注解
⚫ 位置:方法定义上方,类定义上方,接口定义上方
⚫ 作用:设置当前类/接口中所有方法或具体方法开启事务,并指定相关事务属性
⚫ 范例:

@Transactional(
readOnly = false,
timeout = -1,
isolation = Isolation.DEFAULT,
rollbackFor = {ArithmeticException.class, IOException.class},
noRollbackFor = {},
propagation = Propagation.REQUIRES_NEW
)

tx:annotation-driven 标签用于开启事务的注解驱动

⚫ 名称:tx:annotation-driven
⚫ 类型:标签
⚫ 归属:beans标签
⚫ 作用:开启事务注解驱动,并指定对应的事务管理器
⚫ 范例:

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

声明式事务(纯注解驱动)

@EnableTransactionManagement 这个注解就是代替上面的标签

⚫ 名称:@EnableTransactionManagement
⚫ 类型:类注解
⚫ 位置:Spring注解配置类上方
⚫ 作用:开启注解驱动,等同XML格式中的注解驱动
⚫ 范例:

@Configuration
@ComponentScan("com.fs")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}

代码演示(代码中注释为详细解释)

数据表account

spring控制事务:声明式事务(注解)_第1张图片

构建maven项目

spring控制事务:声明式事务(注解)_第2张图片

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.fs</groupId>
    <artifactId>day04_spring_AOP_Transaction_02</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <!--        jdbc-->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <!--        spring整合mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <!--        mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.20</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <!--        aop切面包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.93.132:3306/test
jdbc.username=root
jdbc.password=root

编写配置类

SpringConfig
package com.fs.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//表示这个类是一个spring的配置类,并将其存入到ioc容器中
@Configuration
/*开启扫描注解的那些包

    
 */
@ComponentScan("com.fs")
//引入其他的配置类
@Import({JdbcConfig.class,MybatisConfig.class,TransactionManagerConfig.class})
//开启切面自动代理
@EnableAspectJAutoProxy
//开启声明式事务管理    相当于配置文件中的 
@EnableTransactionManagement
public class SpringConfig {
}

JdbcConfig
package com.fs.config;


import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

/*

    
 */
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
    //@Value("${Key}")
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    /*
    
    
        
        
        
        
    
     */
    //将返回的DruidDataSource交给ioc管理
    @Bean
    public DruidDataSource getDruidDataSource(){
        //创建DruidDataSource
        DruidDataSource druidDataSource = new DruidDataSource();
        //给属性赋值,这个是上面从配置文件中依耐注入给属性的
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        //返回DruidDataSource,然后交给ioc管理
        return druidDataSource;
    }
}

MybatisConfig
package com.fs.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class MybatisConfig {


    /*
        
    

        

        
    
     */
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
        //创建sql会话工厂类                                //这里@Autowired也是从ioc拿DataSource
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //从ioc容器中取出jdbcConfig中配置的druidDatasource
        sqlSessionFactoryBean.setDataSource(dataSource);
        //配置起别名
        sqlSessionFactoryBean.setTypeAliasesPackage("com.fs.pojo");
        return sqlSessionFactoryBean;
    }

    /*
    
    

        
    
     */
    //创建MyBatis动态代理扫描类
    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){
        //创建映扫描配置类
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        //设置动态代理扫描的dao的包
        mapperScannerConfigurer.setBasePackage("com.fs.dao");
        //交给spring管理
        return mapperScannerConfigurer;
    }
}

TransactionManagerConfig
package com.fs.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/*
声明式事务配置类
 */
public class TransactionManagerConfig {

    /*
    
    
        
    
     */
    @Bean
    public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
        //使用Spring的平台事务管理器,是一个接口,使用他的实现类构造器传递一个连接池
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        //传递一个连接池
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

实体类

Account
package com.fs.pojo;

import lombok.Data;

@Data
public class Account {
    private Integer id;
    private String name;
    private Double money;
}

Dao

AccountDao
package com.fs.dao;

import com.fs.pojo.Account;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

public interface AccountDao {
    @Select("select * from account")
    List<Account> findAll();//查询所有

    //根据名字修改money
    @Update("UPDATE account SET money = #{money} WHERE name = #{name}")
    void transferMoney(Account account);

    //根据名字查询账户信息
    @Select("select * from account where name = #{name}")
    Account findAccountByName(@Param("name") String name);
}

service

AccountService
package com.fs.service;

import com.fs.pojo.Account;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/*
在接口上配置@Transactional,那么他下面的实现类都会进行事务管理
这个注解就相当于配置文件中的这些配置
    
        
            
        
    
    
        
        
    

如果不写属性,该注解的默认配置为
    @Transactional(
        readOnly = false,
        timeout = -1,
        isolation = Isolation.DEFAULT,
        rollbackFor = {ArithmeticException.class, IOException.class},
        noRollbackFor = {},
        propagation = Propagation.REQUIRES_NEW
    )
 */
public interface AccountService {
    List<Account> findAll();

    Account findAccountByName(String name);

    //对这个方法开启事务使用默认配置
    @Transactional
    void transferMoneyAtoB(String aName,String bName,Integer money);
}

AccountServiceImpl
package com.fs.service.impl;

import com.fs.dao.AccountDao;
import com.fs.pojo.Account;
import com.fs.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.List;

/*
    
    

        
    
 */
@Service
public class AccountServiceImpl implements AccountService {

    //从ioc获取MyBatis动态代理的accountDao实现类
    @Autowired
    private AccountDao accountDao;

    @Autowired
    private DataSource dataSource;

    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }

    @Override
    public Account findAccountByName(String name) {
        return accountDao.findAccountByName(name);
    }

    //转账的业务实现
    @Override
    public void transferMoneyAtoB(String aName, String bName, Integer money) {
        //先查出两个人的数据
        Account aAccount = accountDao.findAccountByName(aName);
        Account bAccount = accountDao.findAccountByName(bName);

        //然后a减钱,b加钱
        aAccount.setMoney(aAccount.getMoney()-money);
        bAccount.setMoney(bAccount.getMoney()+money);


        //然后调用转账方法(sql语句为更新账户)
        accountDao.transferMoney(aAccount);
        //制作一个异常
//        int i = 1/0;
        accountDao.transferMoney(bAccount);
    }

}

测试类

package com.fs.service.impl;

import com.fs.config.SpringConfig;
import com.fs.pojo.Account;
import com.fs.service.AccountService;
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;

import java.util.List;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceImplTest {

    @Autowired
    private AccountService accountService;

    //测试查询所有方法
    @Test
    public void findAll() {
        List<Account> all = accountService.findAll();
        System.out.println(all);
    }

    //测试转账方法已经使用@Transactional绑定事务
    @Test
    public void transferMoneyAtoB() {
        //测试转账方法
        accountService.transferMoneyAtoB("小付","小花",100);
    }

}

执行效果

业务层转账方法正常运行成功后数据表数据

由于我们测试代码中是小付向小花转账100元,代码执行成功后应该小付900,小花1100
spring控制事务:声明式事务(注解)_第3张图片
业务层转账方法我们给制作一个异常1/0 的/ by zero异常,
运存测试转账方法控制台输出
spring控制事务:声明式事务(注解)_第4张图片
数据库中表的数据
小付原本900,小花1100,我们进行了转账业务,但是制作了异常,事务会进行回滚,所以金额不会发生变化

spring控制事务:声明式事务(注解)_第5张图片

你可能感兴趣的:(Spring,spring)