Spring学习__一篇足矣

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: Spring学习__一篇足矣

@TOC

1.Spring简介

1.1概述

Spring: 春天,也就是给==软件行业==带来了春天!
Spring理念: 他使得现有的计数更加容易使用, 本身是一个大杂烩, 整合现有的技术框架!

SSM: SpringMVC + Spring + Mybatis

导入对应jar包

在这里插入图片描述

1.2 优点
●Spring是一个来源的免费框架(容容器)
●Spring是一个轻量级的(需要的jar包都非常小), 非入侵式的框架,!
●控制翻转(IOC), 面向切面编程(AOP)!
●支持事务的处理, 对框架整合的支持!

总结: Spring就是一个轻量级的,非侵入式的,控制反转(IOC) 和面向切面编程(AOP)的框架!

1.3 拓展

在这里插入图片描述
●Spring Boot
○一个快速开发的脚手架
○基于SpringBoot可以快速开发的单个微服务
○约定大于配置
●Spring Cloud
○SpringCloud 是基于SpringBoot实现的

因为现在大多数公司都在用SpringBoot进行快速开发, 学习SpringBoot前提是完全掌握Spring以及SpringMVC

弊端: 发展太久, 违背原来理念, 配置十分繁琐,简称"配置地狱"

2、IOC编程理论编程

在之前的编程,需要 业务层( service )来实现具体的的dao层方法

这种业务, 用户需求会影响原来的代码, 需要根据需求去修改原代码, 修改代价是十分昂贵的

此时我们使用一个Set接口实现, 发生革命性变化(简称构造器注入)

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/2d0115c1fa94490c9187817f4d5840e3.png)
●之前, 程序是主动的创对象, 控制权在程序员手上

●在使用set注入以后, 程度不再具有主动性, 而是变成了被动接收对象

这种思想 , 从本质上解决了问题, 我们程序员再也不用去管理对象的创建了. 这样系统的耦合性就大大降低了, 可以更加专注的在业务的实现上! 这是IOC的原型

## 3、IOC

**IOC本质:**
>控制反转Ioc,是一种设计思想, DI注入是实现Ioc的一种方法
>Ioc是Spring框架的核心内容, 使用多种方式完美的实现Ioc, 可以使用XML配置, 也可以使用注解
>
○采用XML方式配置Bean的时候, Bean的定义信息是和实现分离的,
○而采用注解的方式可以把两者为一体, Bean的定义信息会直接以注解的形式定义在实现类里
**控制反转是一种通过描述(XML/注解)并通过第三方去生产或者获取特定对象的方式,在Spring里实现控制反转是Ioc容器,** 


>IOC容器:
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/27898fa3f6e145ee80962dcd1b38a25a.png)
Hello这个对象是由Spring创建的
属性是由Spring容器设置的


>测试类![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/99770e5e76b24819a2c0cf76bf78d1fa.png)


所谓的IOC就是由Spring来创建,管理,装配

>之后再将业务层对象放入ICO容器里
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/c508c297ca274aafa3284b46ed851f05.png)

这样就连创建业务层对象(mysqlIml)都不用创建了,直接用UserServiceImpl对象就可以
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/29cc190cfb1c45a88365cabeb808eed5.png)

## 4、IOC创建对象方式
<1>**使用无参构造创建对象, 这是默认的**
<2>如果要使用有参构造来创建对象,就要更改bean文件
1.  下标赋值
  第一种,下标赋值

```sql
第一种方式, 下标赋值
<bean id="user" class="com.jwq.pojo.User">
   <constructor-arg index="0" value="井wq"/>
</bean>
  1. 类型赋值
    <!--第二种方式,通过类型创建, 不建议使用-->
    这是通过构造方法来创建
    <bean id="user" class="com.jwq.pojo.User">-->
        <constructor-arg type="java.lang.String" value="井wq"/>-->
    </bean>-->
  1. 通过参数名来设置
    <!--第三种方式, 直接通过参数名来设置-->
    <bean id="user" class="com.jwq.pojo.User">
        <constructor-arg name="name" value="井wq"/>
    </bean>

<3>配置文件加载就将所有对象创建
首先在bean.xml文件里注册对应的pojo
在这里插入图片描述
然后再容器里获取user的对象
在这里插入图片描述
最后发现就算是使用user对象,那么userT对象也会被实例化

在这里插入图片描述

总结:
在spring创建对象(控制反转)时, 还需要为我们的对象属性进行初始化赋值, 这个过程叫做==依赖注入==
在配置文件加载的时候, 容器中管理的对象就已经被初始化了

5、Spring配置

5.1、别名

```sql
 <!--1.别名, 如果添加了别名, 我们也可以使用别名来获取这个对象-->
    <alias name="user" alias="userNew"/>

5.2、Bean的配置


```sql
     <!--2.bean对象
            id: bean的唯一表示符, 也就相当于我们学的对象名
            class:是bean对象所对应的全限类名 : 包名+类名
            name: 也就是别名,而且name 可以同时取多个别名
        -->
    <bean id="userT" class="com.jwq.pojo.UserT" name="userTNew,userTNewNew">
        <property name="name" value="井井井"/>
    </bean>

5.3、<import>

一般用于团队开发使用, 他可以将多个配置文件, 导入并合并成一个
如下图,将多个resources下的beans.xml文件导入一个总的applicationContext.xml文件里, 使用时直接用总的配置文件就可以
在这里插入图片描述

6、依赖注入

6.1、构造器注入

就是之前的Set注入
在这里插入图片描述

6.2、*Set方式注入
●依赖注入: Set注入!
○依赖: bean对象的创建依赖于容器
○注入: bean对象中所有的属性, 由容器来注入
[环境搭建]

  1. 复杂类型
public class Address {
   
   
    private String address;

    public String getAddress() {
   
   
        return address;
    }

    public void setAddress(String address) {
   
   
        this.address = address;
    }
}
  1. 真实类型
public class Student {
   
   
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
    }
  1. beans.xml
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- xmlns:p="http://www.springframework.org/schema/p"是添加的行 -->

    <bean id="student" class="com.jwq.pojo.Student">
        <!-- 第一种 普通值注入 value 通过set方法注入-->
        <property name="name" value="井wq"/>
        <!-- 第二种 通过构造方法注入-->
        <constructor-arg name="id" value="100"></constructor-arg>
    </bean>
</beans>
  1. 测试类
public class MyTest {
    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student studnet = (Student) context.getBean("studnet");
        System.out.println(studnet.getName());
    }
  1. 完善注入信息

在这里插入图片描述

6.3、拓展方式注入
我们可以使用P命令或者C命名空间
配置beans.xml的约束
在这里插入图片描述

测试:

     @Test
    public void test(){
   
   
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user2", User.class);
        System.out.println(user);
    }

注意点: p命名和c命名空间不能直接使用,需要导入xml约束

6.4、bean的作用域
在这里插入图片描述

  1. 单例模式(Spring默认机制)

    scope="singleton"

    <bean id="user" class="com.jwq.pojo.User" p:name="井wq" p:age="21"
    scope="singleton"/>
  1. 原型模式: 每次从容器get时候,就会产生一个新对象!
    <bean id="user" class="com.jwq.pojo.User" p:name="井wq" p:age="21"
    scope="prototype"/>
  1. 其余的requset, session, application(全局),这些只能在web开发里用到!

7、Bean的自动装配

●自动装配是Spring满足bean依赖的一种方式
●Spring会在上下文里自动寻找, 并且自动给bean装配属性

在Spring里有三种装配的方式

  1. 在xml中显示的配置
  2. 在java里显示配置
  3. *隐式 的自动配置bean

7.1、测试
环境搭配: 一个人有两个宠物

7.2、ByName自动装配

     <bean id="cat" class="com.jwq.pojo.Cat"/>
     <bean id="dog" class="com.jwq.pojo.Dog"/>

<!--   bean的自动装配: autowire
            autowire="byName"  他会自动在容器上下文查找, 和自己对象set方法后面的值对应的beanid!-->
    <bean id="people" class="com.jwq.pojo.People" autowire="byName">
        <property name="name" value="井文强啊"/>
    </bean>

必须beanid与该bean对象的set方法的参数名一致,且上面的bean必须有id
7.2、ByType自动装配

 <bean class="com.jwq.pojo.Cat"/>
    <bean class="com.jwq.pojo.Dog"/>

<!-- autowire="byType"  他会自动在容器上下文查找, 和自己对象属性类型相对应的bean!  就算没有beanid也可以自动注入-->
    <bean id="people" class="com.jwq.pojo.People" autowire="byType">
        <property name="name" value="井文强啊"/>
    </bean>

用byType时候,需要保证所有bean的class唯一, 并且这个bean和需要自动注入的属性的类型一致

7.3使用注解来实现自动装配

要使用注解须知:

  1. 导入约束 context约束
  2. 配置注解的支持
    注意 :
    开启注解的支持:
    1. 首先引入支持
      在这里插入图片描述
      1. 开启注解扫描

@Autowired
这是框架里得自动注入标签,他可以自动的去Spring容器里去查找当前类型的对象
或者通过名称去查找,就要结合注解@Qualifier("bean名称")

直接使用在该类的属性上即可, 也可以在set方法上使用
使用Autowired时候, 我们可以不用再去编写Set方法, 前提是这个自动装配的属性在IOC(Spring) 容器里有对应的bean,且符合名字byName
在这里插入图片描述

如果有多个该ICO容器里有多个bean对象, @Autowired就无法找到对应的bean对象
在之前的版本, 如果@autowired自动装配的环境比较复杂,自动装箱无法通过注解完成,就可以使用@Qualifier(value="对应id")配合@autowired的使用在这里插入图片描述

@Resources注解

这是java里的注解
在这里插入图片描述

小结:
@Resouces和@Autowired区别

●都是用来自动装配, 都可以放在属性字段上
●@Autowired是通过byType来实现的
●@Resources 是默认通过byName方式实现的, 如果找不到名字,就通过byName方式! 如果都找不到就报错!

8、使用spring里封装的jdbc功能

8.1 jdbc封装

  1. 导入jdbc模块依赖
  2. 导入mysql
  3. 导入阿里巴巴的数据源管理组件

    数据源组件封装了连接数据库功能, 还有数据连接池功能

 <!-- spring-jdbc -->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>5.2.2.RELEASE</version>
 </dependency>
 <!--mysql-connector-java-->
 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>8.0.16</version>
 </dependency>
 <!-- 阿里数据源 -->
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid</artifactId>
     <version>1.1.10</version>
 </dependency>

可以将配置jdbc功能配置文件写到外面, 再在spring中导入
在这里插入图片描述
将连接数据的数据放到.properties文件里

在这里插入图片描述
数据源的配置
在这里插入图片描述

9、使用注解开发

在Spring4之后, 要使用注解开发, 就必须要保证 aop的包导入
在这里插入图片描述
使用注解需要导入context约束, 增加注解的支持

<?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"
       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">

    <!--    开启注解的支持-->
    <context:annotation-config/>

</beans>

9.1 如何将对象放入IOC容器
使用注解@Component
相当于是
在这里插入图片描述

9.2 属性如何注入

在这里插入图片描述

    /*
        @Autowired  spring
            框架里提供的一个自动注入注解标签
                有两种方式去查找对象:
                1. byType 去spring容器中根据当前的类型去寻找
                2. byName  通过名称去查找,需要结合注解--->@Qualifier("adminDao")
        @Resource()
            jdk中提供注解标签
                有两种方式去查找对象:
                1. byType 去spring容器中根据当前的类型去寻找
                2. byName  通过名称去查找,需要结合name---> @Resource(name = "adminDao")
                @Autowired(require=true)  他在注入时候, 对象值不能为空

     */

9.3 衍生的注解
@Component 有几个衍生注解, 我们在web开发中, 会按照mvc三层架构分层
○dao[@Repository]
○service [@Service]
○controller[@Controller]
这四个注解功能都是一样的, 都是代表将某个类注册到Spring里, 装配Bean
9.4 自动装配属性的标签

 -@Autowired :自动装配通过类型,名字
        如果Autowired不能唯一自动装箱上属性, 则可以结合注解@Qualifier(value="对应id")
-@Resources: 自动装配通过名字, 类型

9.6 作用域
@Scope("prototype")

@Component
@Scope("prototype")/singleton 
public class User {
   
   
    //相当于<property name="mame" value="jingwenqiang"/>
    @Value("jingwenqiang")
    public String name;
}

9.7 小结

xml与注解:
○xml更加万能, 适用于任何场所! 维护简单方便
○注解 不是自己类使用不了, 维护相对复杂!

xml 与 注解最佳实践:
○xml 用来管理bean
○注解只负责完成属性的注入

使用注解前:

1.导入注解的支持
2.扫描指定的包, 包下的注解就会生效
在这里插入图片描述

10、使用java的方式配置spring

我们现在要完全不使用Spring的xml配置了, 全权交给java来做

实体类

//这里的注解意思是, 就是说这个类被Spring接管了, 注册到了容器里
@Controller
public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }
    @Value("jingwenqiang")//属性注入
    public void setName(String name) {
        this.name = name;
    }
}

配置文件

//这个也会被Spring容器托管, 注册到容器里,因为他本来就是一个@Component
//@Configuration表示一个配置类,就和我们之前的beans.xml
@Configuration
@ComponentScan("com.jwq.pojo")//显示的扫描包
@Import(JingConfig2.class)//引入其他配置类,使其融合一个
public class JingConfig {
   
   

    //注册一个Bean就相当于与之前写的一个bean标签
    //方法名就相当于bean里的id属性
    //这个方法的返回值, 就相当于bean标签里的class属性
    @Bean
    public User getUser(){
   
   
        return new User();//就是返回要注入bean的对象
    }
}

测试类

public class MyTest {
   
   

    public static void main(String[] args) {
   
   
        //如果完全使用配置去做, 我们就只能通过 AnnotationConfig 上下文来获取容器, 通过配置类的class对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(JingConfig.class);
        User getUser = (User)context.getBean("getUser");
        System.out.println(getUser.getName());
    }
}

这纯java的配置方式, 在SpringBoot中随处可见

11、代理模式

这是SpringAOP的底层
[重点: SpringAOP 和 SpringMVC]

代理模式分类:
●静态代理
●动态代理

11.1、静态代理

●抽象角色: 一般会使用接口或者抽象类来解决
●真实角色: 被代理的对象
●代理角色: 代理真实角色, 代理真实角色后 一般还有一些附属操作
●客户: 访问代理对象的人

就是说,代理角色在不影响真实角色情况下,还可以增加自己的一些功能, 就算出错也不影响真实角色
放到代码层面上说, 就是增加静态代理之后,可以给静态代理增加一些功能方法, 并且不改变原来的代码

业务层代码:

public interface UserService {
   
   

    //增加的方法
    void add();

    //删除的方法
    void delete();

    //更改的方法
    void query();

    //查询的方法
    void find();
}

具体实现类:

    public void add() {
   
   
        System.out.println("这是增加的方法");
    }

    public void delete() {
   
   
        System.out.println("这是删除的方法");
    }

    public void query() {
   
   
        System.out.println("这是更改的方法");
    }

    public void find() {
   
   
        System.out.println("这是查询的方法");
    }
}

此时客户想增加一些功能,比如说打印日志, 如果贸然更改原代码,万一就出错就会很麻烦,所以此时就用一个代理模式解决此问题

代理类:

public class UserServiceProxy implements UserService{
   
   

    private UserServicelmpl userService;


     //此处想代理那个业务层就把那个业务层对象丢进去
    public void setUserServicelmpl(UserServicelmpl userService){
   
   
        this.userService = userService;
    }

    public void add() {
   
   
        log("add");
        userService.add();
    }

    public void delete() {
   
   
        log("delete");
        userService.delete();
    }

    public void query() {
   
   
        log("query");
        userService.query();
    }

    public void find() {
   
   
        log("find");
        userService.find();
    }

    //打印日志的方法
    public void log(String msg){
   
   
        System.out.println("[Debug] 使用了"+msg+"方法");
    }
}

客户层:

public class Client {
   
   

    public static void main(String[] args) {
   
   
        //原来的业务层
        UserServicelmpl userServicel = new UserServicelmpl();

        //增加的代理对象
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserServicelmpl(userServicel);
    }
}

==代理模式的好处==
●可以使得真实角色操作更加纯粹 , 不用再去关注公共的业务
●公共也就交给代理角色, 实现了业务的分工
●公共业务发生扩展时候, 方便集中管理

缺点:
●一个真实角色会产生一个代理角色; 代码量会翻倍,开发效率变低

11.2、动态代理
优点:
除静态代理好处外, 还有
一个动态代理类代理是一个接口, 一般就是对应的一类业务
一个动态代理类可以代理多个类, 只要实现同一个接口就行

动态处理特点:
●动态代理和静态角色一样
●动态代理的代理类是动态生成的, 不是我们直接写好的
●动态代理分为两大类: 基于接口的动态代理, 基于类的动态代理

 1. 基于接口 -----JDK动态代理
 2. 基于类: cglib
 3. java 字节码实现: javasist

动态代理两个类:
Proxy: 他是代理
InvocationHandler: 用来调用处理程序的方法

在这里插入图片描述

12、AOP

12.1 什么是AOP?
AOP: 面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP是OOP的延续, 是软件开发的一个热点, 也是Spring框架里一个重要的部分. 使用AOP可以对业务逻辑的各个部分进行隔离, 从而使得业务逻辑各个部分之间的耦合度降低, 提高了程序的可重用性, 同时提高了开发效率

==注意:==对于AOP这种编程思想, 很多框架都进行实现. spring就是之一,可以完成切面编程

具体实现: spring引入叫做AspectJ的aop框架
12.2 引入AOP

方式一: 使用配置 完成aop

  1. 下载AOP相关的jar
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
  1. 基于aspect的xml配置方式实现
<!-- 将具体类给spring, 让他管理-->
<bean id="aopdemo" class="com.ff.spring.aop.AopDemo"></bean>
<aop:config>
    <!-- 配置切入点 -->
    <aop:pointcut expression="execution(*
    com.ff.spring.service.UserService.adduser(..))" id="adduser"/>
    <aop:pointcut expression="execution(*
    com.ff.spring.service.UserService.*(..))" id="allmethod"/>
    <!-- 配置通知和切入点 -->
    <aop:aspect ref="aopdemo">
    <aop:before method="savelog" pointcut-ref="adduser"/>
    <aop:after method="savelog" pointcut-ref="adduser"/>
    <aop:around method="aroundAdvice" pointcut-ref="adduser"/>
    <aop:after-throwing method="exceptionAdvice" pointcut-ref="allmethod"
    throwing="e" />
    </aop:aspect>
</aop:config>

在这里插入图片描述

execution表达式的结构解释
在这里插入图片描述

配置==通知==:

通知有分为5种:
前置通知(before) 业务方式执行前掉调用
后置通知(after-returning) 业务方法执行后调用, 当方法出现异常不执行
异常通知(after-throwing) 业务方法出现异常时调用
最终通知(after) 业务方法执行后调用, 出现异常继续调用

   环绕通知(around)可以包含前四个通知
          环绕通知例子:    
            public void aroundAdvice(ProceedingJoinPoint point){
                try {
                    System.out.println("前置通知");
                    point.proceed();//调用我们自己的方法
                    System.out.println("后置通知");
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                    System.out.println("异常通知"+throwable.getMessage());
                }
                System.out.println("最终通知");
            }

在这里插入图片描述

简而言之: 就是将程序里的一些非业务代码进行隔离, 在不需要修改原来的代码的情况下, 为程序添加额外加的功能
非业务代码: (验证权限, 打印日志, 提交事务, 统一异常处理)
底层实现: 是使用动态代码模式

代理对象 : 告诉代理对象, 调用哪个方法时,让代理对象去帮助我们调用哪个方法

11.2 AOP在Spring里的作用
==提供声明式事务: 允许用户自定义切面==
在这里插入图片描述

方式二: 使用Spring注解实现AOP

条件:

  1. 使用Aop织入, 需要导入一个依赖包
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-aspects</artifactId>
             <version>5.2.2.RELEASE</version>
         </dependency>
    
  2. 还要开启注解与自动代理
    在这里插入图片描述
  3. 给待切入方法的类 和 该类方法添加注解

在这里插入图片描述

这里的PrceedingJoinPoint对象是封装了上面注解里的方法

13、spring里封装的事务

事务
事务管理是数据库提供的一种功能, 为了保证数据过程的准备性, 管理一种中有多个单元

关系型数据库事务基本特征:

  1. 原子性特征: 一次操作多条sql,要么都执行, 要么都不执行
  2. 隔离性
  3. 持久性
  4. 一致性
    spring中的事务管理分为两种形式:

一、声明式事务

建立在AOP的基础上的, 本质是对方法前后进行拦截, 声明式事务是方法级别的
使用注解标签实现
声明式事务管理

<1>基于xml的配置

<2>基于注解的实现

  1. 引入约束
    在这里插入图片描述
    <2> 配置 spring 事务管理列, 注入事务源,再开启事务管理
    在这里插入图片描述
    <3>在方法上添加@Transactional注解
    在这里插入图片描述

二、编程式事务

在在代码中自己写的
在这里插入图片描述

事务管理标签@Tansactional总结

  1. 如果加在类上面, 表示该类所有方法都会添加事务管理的功能
    加方法上,就表示此方法会添加事务管理的功能
  2. 一般不在Dao层添加Transactional, 具体看下面的转钱操作

三、声明式事务不生效的场景:

    @Transactional一下六种情况下会失效:
        1. @Transactional 底层权限只针对public修饰的方法
        2. 方法里的异常被catch捕获处理了
        3. 出现编译器异常, 事务不生效, 底层是针对运行期异常
            默认情况下是针对运行期异常进行捕获 Transactional(rollbackFor = RuntimeException.class)
            可以将其修改成rollbackFor = Exception.class, 这样就可以处理任何时期的异常
        4. @Transactional事务传播行为设置错误
        5. 数据库引擎不支持事务, 是mysql底层具体的一种数据处理实现的机制
            innodb(支持事务功能), myisam
        6.  在一个非事务方法里使用this(原始的对象==自己new出来的对象)去调用加事务管理标签的方法

如果添加在一个业务操作需要调取多个SQL的dao层,就会出错如下代码演示
背景设置: 1号id有1000元, 1号要给2号转账500元

代码如下

dao层:

这里直接给底层的dao数据访问层添加@transactional注解

//应用于数据访问层@Repository(value = "adminDao")
@Repository(value = "adminDao")
public class AdminDao {
   
   

    @Autowired
    JdbcTemplate jdbcTemplate;//这是spring内部封装jdbc的类

    @Transactional
    public void saveMoney(int money, int id){
   
   
        jdbcTemplate.update("update admin set money=money-"+money+" where id= ?",id);
    }
    @Transactional
    public void addMoney(int money, int id){
   
   
        jdbcTemplate.update("update admin set money=money+"+money+" where id=?",id);
    }
}

service层:

@Service(value = "adminService")
public class AdminService {
   
   
    @Autowired
    @Qualifier("adminDao")
    AdminDao adminDao;

    public AdminDao getAdminDao() {
   
   
        return adminDao;
    }

    public void setAdminDao(AdminDao adminDao) {
   
   
        this.adminDao = adminDao;
    }

    public void tansferAccounts(){
   
   
        this.adminDao.saveMoney(500,1);
        //这里制造一个算数异常
        int a = 10/0;
        this.adminDao.addMoney(500,2);
    }
}

测试:

public class Test {
   
   

    public static void main(String[] args) {
   
   

        //读取spring配置文件, 并且对文件里的配置对象进行创建
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
            //Object admin = app.getBean("admin");由于spring不知道该类的类型,所以就返回Object类型
        Admin admin = app.getBean("admin", Admin.class);
        AdminService adminService = app.getBean("adminService",AdminService.class);
        adminService.tansferAccounts();
    }
}

在Webyog(数据库可视化工具)查看结果,发现账户1的钱从1000变成了500, 减过了, 但是账户2没有加钱还是0,所以dao层只有savaMoney()执行了, addMoney()没有执行, 就生错误了
在这里插入图片描述
原因分析: 由于service层的算数错误,导致下面代码运行不了, 所有减钱方法执行.价钱方法不执行

解决方案:

只要把事务注解标签@Transctional添加到service层上面就可以解决问题了, 由此可见@Transctional标签不能加在一个业务操作多个dao层的SQL上,要把这些sql放在同一个事务管理标签上面


四、Spring事务传播行为

是spring框架自己额添加的功能, 不属于事务实际提供者mysql

在一个有事务方法里,调用另一个有事务的方法, 那么, 另一个有事务的方法应该如何执行,== 是两个事务合二为一还是独立的==
spirng里事务传播行为有7种:

  1. Propagation.REQUIRED
    在这里插入图片描述
    如果存在事务就加入, 没有事务就新建

         A事务方法去调用B方法,传播行为Required, 加入到A方法中, 任意一方出现错误都会回滚
         A方法没有事务, 调用B方法传播行为是Required, B会新建一个事务, 与A没有关系
    
  2. Propagation.REQUIRES_NEW
    在这里插入图片描述
    propagation = Propagation.REQUIRES_NEW)

         A事务方法, 调用B方法传播行为REQUIRES_NEW  无论是否有事务存在都会创建一个独自的事务
         A方法没有事务 , 调用B方法传播行为REQUIRES_NEW  无论是否有事务存在都会创建一个独自的事务
    
  3. Propagation_Never
    在这里插入图片描述
    如果A方法有事务就会报错

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4天前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
4天前
|
前端开发 JavaScript Java
6个SpringBoot 项目拿来就可以学习项目经验接私活
6个SpringBoot 项目拿来就可以学习项目经验接私活
43 0
|
4天前
|
前端开发 Java 数据库
基于springboot的书籍学习平台
基于springboot的书籍学习平台
|
4天前
|
SpringCloudAlibaba Java 持续交付
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
204 0
|
4天前
|
XML Java 应用服务中间件
【JavaEE】JavaEE进阶:框架的学习 - Spring的初步认识
【JavaEE】JavaEE进阶:框架的学习 - Spring的初步认识
9 0
|
4天前
|
Java 开发工具 Maven
根据SpringBoot Guides完成进行示例学习(详细步骤)
根据SpringBoot Guides完成进行示例学习(详细步骤)
8 1
|
4天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
17 1
|
4天前
|
Java 数据安全/隐私保护 Sentinel
微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流
微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流
|
4天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
4天前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架