首页 > 其他分享 >Spring—事务

Spring—事务

时间:2023-02-06 21:14:09浏览次数:38  
标签:事务 String Spring class money public name

前言

一觉醒来下雨了,今天还是蛮冷的,坐标无锡,及时添衣服啊。话说最近喜欢上了看衬衫,对格子衬衫感兴趣了(据说格子衬衫是程序员的标配,是我越来越像程序员了么...)。早上从床上爬起来就开始看视频了,之所以看了一天才更新那么一点,是因为对每个代码都有上机实践。实践的过程可就太痛苦了,不报错还好,报错也没事,最怕的就是不报错的bug,动辄花费几十分钟。。。好了废话不多说了,直接进入今天的主题,Spring的事务部分。

 


不知道大家有没有注意过银行转账的逻辑,很简单对吧。就是客户A向客户B转了C元钱,那么A对应的账户就需要减去C元,B对应的账户就要加上C元。使用Spring整合JDBC和Mybatis可以轻松完成这一业务逻辑。那么我先来演示一下如下过程。很简单的一张表哈,在tbl_account表中有两行记录,分别记录的Tom和Jerry两人的余额。在idea中使用配置文件的方式链接到数据库。

 

然后在主包下面的Config包下配置JdbcConfig的类。(节省篇幅,折叠一下啦)

 

public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    private DataSource dataSource(){
        DruidDataSource ds=new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
View Code

 

同样的,由于整合了Mybatis来对sql语句进行简化,也要在Config包下书写一个MybatisConfig类。

 

public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("study.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc=new MapperScannerConfigurer();
        msc.setBasePackage("study.dao");
        return msc;
    }
}
View Code

 

在这两步都结束了之后,就开始书写Spring的配置文件的,非常简单哈。

 

1 @Configuration                        //注解声明其为配置文件
2 @ComponentScan("study")                   //扫描主包中的bean
3 @PropertySource("classpath:jdbc.properties")      //声明配置文件的来源
4 @Import({JdbcConfig.class, MybatisConfig.class})    //导入刚刚配置好的JdbcConfig和MybatisConfig
5 public class SpringConfig {
6 }

 

在主包下新建一个包(名字任取),用于放置数据类型,此处我用的是Account类型。

public class Account {
    Integer id;
    String name;
    Double money;
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
View Code

 

在dao层来书写转出和转入的接口,用于后面service层的调用。

public interface AccountDao {
    @Update("update tbl_account set money = money + #{money} where name = #{name}")
    void inMoney(@Param("name") String name,@Param("money") Double money);      //@Param后面表示为该参数设置一个名字,后续就会将其传递到上面的sql语句中
    @Update("update tbl_account set money = money - #{money} where name = #{name}")
    void outMoney(@Param("name") String name,@Param("money") Double money);
}

最后来实现一下Service层即可,包括了service的接口和Impl。

public interface AccountService {
    public void transfer(String out,String in,Double money);
}
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private LogService logService;
    @Override
    public void transfer(String out, String in, Double money) {
            accountDao.inMoney(in,money);
            accountDao.outMoney(out,money);
    }
}

上述内容实现了之后,就写一个test来测试一下这个功能是否合格吧!(要整合JUnit,后面我会把需要的依赖的坐标都附上,供大家使用,当然版本不同,请甄别!)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= SpringConfig.class)
public class AccountServiceTest {
    @Autowired
    private AccountService accountService;
    @Test
    public void testTransfer() throws IOException {
        accountService.transfer("Tom","Jerry",100D);
    }
}

回到库中查看结果,可以发现,Tom和Jerry的余额都已经被修改,可以说这个功能做好了。。。。。吗?真的做好了吗?

 

 

在现实生活中,转账并非一瞬间的事情,人们的转账也并非一帆风顺,可能转账期间恰逢系统维护,那么转账的钱又将何去何从呢?我用一个简单的例子来验证一下,如果在刚刚的转账方法

处加入一个错误,例如int i=1/0,那么众所周知,程序会报错,还有呢?试着运行就可以发现,程序正常报错了,然而转账却出了问题,可以发现,Tom的资金并没有产生变化,而Jerry的长上却多出来了100块钱,对于Jerry来说是件好事,但对银行来说,就是破产的预告啦!由此可见,上面的方法还是有很大漏洞的!那么该如何解决这个问题呢?这时,就要引入今天的主角了—Spring的事务处理。

什么是Spring的事务?

事务就是逻辑上的一些组合,事务要么一起成功,要么一起失败(同成功,共失败)。比如刚刚的转账事务,在这个方法运行中,执行转账方法是一个事务,Tom扣钱是一个事务,Jerry加钱是一个事务,产生/0报错也是一个事务。那么当转账采用事务管理后,整个流程就合并成一个事务了,在此期间只要有一个出了问题,那么整个事务都会运行失败,里面的操作自然就会回滚,从而保持数据的安全。同样的,只有当所有的操作都成功了,那么整个事务才会成功。这就是Spring的事务管理。

那么如何开启事务呢?

很简单,只需要几步就能搞定。还记得上面的SpringConfig吗?

第一步:给要进行事务管理的方法对应的接口上配置注解@Transactional,降低藕合的同时,声明了这是一个事务。

第二步:在config包下的JdbcConfig中定义一个事务管理器,将其声明为一个Bean交给Spring管理

1     @Bean
2     public PlatformTransactionManager transactionManager(DataSource dataSource){
3         DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
4         transactionManager.setDataSource(dataSource);
5         return transactionManager;
6     }

第三步:告诉Spring,现在使用了事务管理,只需要在SpringConfig类上加上一个注解@EnableTransactionManagement就好了。

接着来运行一下看看,对于同样的/0异常,可以发现程序是正常报错的,在数据库中发现,Tom和Jerry的金额都没受到该异常的影响,数据并未提交,而是回滚了,可见事务管理十分成功!

事务相关配置

 

这些是事务还具有的方法,这边就不多阐述了,可以在api中查到对应的用法。

 


 

结束语

那么今天的学习分享就到这里了,下面附录一些常用的依赖坐标供大家参考。 话说各位读者,那么觉得我的内容还有什么可以优化的地方吗?字体什么看的舒服么?如有建议,必然虚心接受!

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.23</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.15</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.18</version>
        </dependency>
    </dependencies>

 

 

 

标签:事务,String,Spring,class,money,public,name
From: https://www.cnblogs.com/garyroyal/p/17096666.html

相关文章

  • Spring循环依赖
    Spring循环依赖面试中也会被常常问到。但是它的整个过程很多人都不知道,什么叫循环依赖呢。多个Bean之间相互依赖,形成一个闭环。如下图(A,B,C分别为Spring容器中3个Bean)就......
  • SpringBoot2.5.6集成mybatis
    1.应用依赖<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version......
  • Spring在Filter中记录Web请求Request和返回Response的内容及时长
    1简介在SpringMVC中,我们有时需要记录一下请求和返回的内容,方便出现问题时排查。比较Header、RequestBody等。这些在Controller也可以记录,但在Filter中会更方便。而我们......
  • SpringBoot响应Json数据乱码通过配置解决
    场景实现把SpringBoot的response编码设置为utf-8找到application.properties配置文件添加如下:#设置响应为utf-8spring.http.encoding.force-response=true 再次刷新浏览器......
  • SpringBoot中自定义消息转化器
    场景1.SpringBoot自动配置了消息转化器。2.自定义消息转化器,只需要在类中添加消息转化器的@Bean,就会被SpringBoot自动加入到容器中。实现新建Controllerpackagecom.exampl......
  • SpringBoot+MyBatis的动态SQL、使用动态SQL时List传值错误解决方案
    目录实现动态SQL的四种方式:1、XML配置2、脚本SQL3、在方法中构建SQL4、结构化SQL关于动态SQL的List传值错误问题1、错误代码2、解决错误实现动态SQL的四种方式:1、XML配置......
  • Spring Cloud Alibaba 在 Proxyless Mesh 上的探索
    站在2023年的今天,ServiceMesh早已不是一个新兴的概念,回顾过去6年多的发展历程,ServiceMesh从一经推出就受到来自全世界的主流技术公司关注和追捧。2016年作为S......
  • spring 重复注解和aop拦截的实现示例
    前言:1:jdk1.8开始支持重复注解@Repeatable实现2:aop拦截需要拦截当前注解和@Repeatable指向的包装注解才可以完全拦截到,因为:1.当在在方法上只有一个注解时,aop拦截......
  • 详解Spring AOP自定义可重复注解没有生效问题
    目录1.问题背景2.不啰嗦,上代码3.问题排查3.1是不是切点写得有问题,于是换成如下形式:3.2是不是使用的地方不是代理对象4.问题原因 1.问题背景工作中遇......
  • Spring AOP使用接口方式实现
    目录一.环境准备二、spring接口方式实现aop步骤1.业务接口实现2.业务类3.通知类4.自定义切##点5.配置xml文件6.方法入口三.分析Spring提供了很多的......