Spring


1、Spring

1.1、简介

  • Spring:春天--->给软件行业带来了春天!

  • 2002年,Rod Jahnson首次推出了Spring框架雏形:interface21框架!

  • spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。

  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

 

  • SSH:Struct2 + Spring + Hibernate!

  • SMM:SpringMVC + Spring + Mybatis!

 

官网:https://spring.io/projects/spring-framework#learn

官方下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring/

GitHub:https://github.com/spring-projects/spring-framework

 

 
 
     org.springframework
     spring-webmvc
     5.3.15
 
 ?
 
 
     org.springframework
     spring-jdbc
     5.3.15
 
 ?

 

1.2、优点

  • Spring是一个开源的免费的框架(容器)!

  • Spring是一个轻量级的,非入侵式的框架!

  • 控制反转(IOC),面向切面编程(AOP)!

  • 支持事务的处理,对框架整合的支持!

 

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

 

1.3、组成

 

1.4、扩展

在Spring的官网有这个介绍:现代化的java开发!说白就是基于Spring的开发!

 

  • Spring Boot

    • 一个快速开发的脚手架。

    • 基于Spring Boot可以快速的开发单个微服务。

    • 约定大于配置!

  • Spring Cloud

    • Spring Cloud是基于Spring Boot实现的

 

因为现在大多数公司都在使用Spring Boot进行快速开发,学习Spring Boot的前提,需要完全掌握Spring 及Spring MVC!承上启下的作用!

 

弊端:发展了太久,违背了原有的理念!配置十分繁琐,人称“ 配置地狱! ”

 

2、IOC理论推导

2.1、分析实现

  1. UserDao 接口

     public interface UserDao {
         void getUser();
     }
  2. UserDaoImpl 实现类

     public class UserDaoImpl implements UserDao{
         @Override
         public void getUser() {
             System.out.println("默认获取用户的数据!");
         }
     }
  3. UserService 业务接口

     public interface UserService {
         void getUser();
     }
  4. UserServiceImpl 业务实现类

 public class UserServiceImpl implements UserService{
 ?
     //private UserDao userDao = new UserDaoMysqlImpl();
     private UserDao userDao;
 ?
     //利用set进行动态实现值的注入!
     public void setUserDao(UserDao userDao) {
         this.userDao = userDao;
     }
 ?
     @Override
     public void getUser() {
         userDao.getUser();
     }
 }

 

测试:

 public class MyTest {
 ?
     public static void main(String[] args) {
 ?
         //用户实际调用的是业务层,dao层他们是不需要接触!
         UserServiceImpl userService = new UserServiceImpl();
 ?
         userService.setUserDao(new UserDaoOracleImpl());
         userService.getUser();
 ?
     }
 }

 

这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

把Userdao的实现类增加

 public class UserDaoMysqlImpl implements UserDao{
     @Override
     public void getUser() {
         System.out.println("客户获取MySQL数据!");
     }
 }
 public class UserDaoOracleImpl implements UserDao{
     @Override
     public void getUser() {
         System.out.println("客户获取Oracle数据!");
     }
 }

紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

 public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoMySqlImpl();
 ?
    @Override
    public void getUser() {
        userDao.getUser();
   }
 }

 

 

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!

 

我们使用一个Set接口实现.已经发生了革命性的变化!

 //private UserDao userDao = new UserDaoMysqlImpl();
 private UserDao userDao;
 ?
 //利用set进行动态实现值的注入!
 public void setUserDao(UserDao userDao) {
     this.userDao = userDao;
 }

 

  • 之前,程序是主动创建对象!控制权在程序猿手上!

  • 使用了set注入后,程序不在具有主动性,而是变成了被动的接收对象!

 

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

 

 

2.2、IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

 

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

 

3、HelloSpring

3.1、编写代码

1、编写一个Hello实体类

 package com.kuang.pojo;
 ?
 public class Hello {
 ?
     private String name;
 ?
     public String getName() {
         return name;
     }
 ?
     public void setName(String name) {
         this.name = name;
     }
 ?
     @Override
     public String toString() {
         return "Hello{" +
                 "name='" + name + '\'' +
                 '}';
     }
 }

2、编写Spring文件,这里命名为beans.xml

 <?xml version="1.0" encoding="UTF-8"?>
 
 ?
     
     
         
     
 ?
 

3、测试

 import com.kuang.pojo.Hello;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 ?
 public class MyTest {
 ?
     public static void main(String[] args) {
         //获取Spring的上下文对象
         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
         //我们的对象都在spring中管理了,我们要使用,直接在里面取出来就好了!
         Hello hello = (Hello) context.getBean("hello");
 ?
         System.out.println(hello.toString());
 ?
 ?
     }
 }

3.2、思考

  • Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的

  • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的

  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

 

3.3、修改案例一,新增一个Spring配置文件beans.xml

 <?xml version="1.0" encoding="UTF-8"?>
 
 ?
     
     
 ?
     
         
     
 ?
     
 

测试:

 import com.kuang.service.UserServiceImpl;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 ?
 public class MyTest {
 ?
     public static void main(String[] args) {
 ?
 //        //用户实际调用的是业务层,dao层他们是不需要接触!
 //        UserServiceImpl userService = new UserServiceImpl();
 //
 //        userService.setUserDao(new UserDaoOracleImpl());
 //        userService.getUser();
 ?
         //获取ApplicationContext,拿到Spring的容器
         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
         //容器在手,天下我有,需要什么,就直接get什么!
         UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");//这里相当于将原来的Service层也IOC了,不需要再在代码中写出调用哪个接口,只需要在配置文件中指明调用的接口即可。
 ?
         userServiceImpl.getUser();
     }
 }

 

OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !

 

4、IOC创建对象的方式

 

  1. 使用无参构造创建对象,默认!

  2. 假如我们要使用有参构造来创建对象。

    1. 下标赋值

       
       
           
       
    2. 类型

       
       
               
       
    3. 参数名

       
       
           
       

 

总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!

 

5、Spring配置

 

5.1、别名


5.2、Bean的配置

 
 
     
 

5.3、import

这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三

  • 李四

  • 王五

  • ApplicationContext.xml

     
     
     

 

使用的时候,直接使用总的配置就可以了!

 

6、依赖注入(DI)

6.1、构造器注入

前面已经说过了

 

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;
         }
     }
  2. 真实测试对象

     public class Student {
     ?
         private String name;
         private Address address;
         private String[] books;
         private List hobbys;
         private Set games;
         private Map card;
         private String wife;
         private Properties info;
         
         //以及get()、set()、toString()方法!
     }
  3. beans.xml

     <?xml version="1.0" encoding="UTF-8"?>
     
     ?
         
             
         
     
  4. 测试

     public class MyTest {
         public static void main(String[] args) {
             ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
             Student student = (Student) context.getBean("student");
             System.out.println(student.getName());
         }
     }

 

1、普通值注入

 
 

2、Bean注入

 
 

3、数组注入



    
        红楼梦
        水浒传
        三国演义
        西游记
    

4、list



    
        听歌
        敲代码
        看电影
    

5、Map



    
        
        
    

6、Set

 
 
     
         LOL
         COC
         BOB
     
 

7、null

 
 
     
 

8、Properties

 
 
     
         000000
         spring
         root
         123456
     
 

 

完善注入信息

 <?xml version="1.0" encoding="UTF-8"?>
 
 ?
     
         
     
 ?
     
         
         
         
         
         
         
             
                 红楼梦
                 水浒传
                 三国演义
                 西游记
             
         
 ?
         
         
             
                 听歌
                 敲代码
                 看电影
             
         
 ?
         
         
             
                 
                 
             
         
 ?
         
         
             
                 LOL
                 COC
                 BOB
             
         
 ?
         
         
             
         
 ?
         
         
             
                 000000
                 spring
                 root
                 123456
             
         
     
 

测试类

 public class MyTest {
     public static void main(String[] args) {
         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
         Student student = (Student) context.getBean("student");
         System.out.println(student.toString());
 ?
         /*
         Student{name='qinjiang',
          address=Address{address='上海'},
           books=[红楼梦, 水浒传, 三国演义, 西游记],
            hobbys=[听歌, 敲代码, 看电影],
             games=[LOL, COC, BOB],
              card={身份证=111111111111111111, 银行卡=111111111111111111},
               wife='null',
                info={password=123456,
                 url=spring,
                  driver=000000,
                    username=root
                    }
                  }
          */
     }
 }

 

6.3、拓展方式注入

我们可以使用 p-namespace 和 c-namespace 进行注入

官方解释:

 

 

先创建一个user实体类

 public class User {
     private String name;
     private int age;
 ?
     public User() {
     }
 ?
     public User(String name, int age) {
         this.name = name;
         this.age = age;
     }
     //以及get、set、tostring

userbeans.xml

 <?xml version="1.0" encoding="UTF-8"?>
 
 ?
     
     
 ?
     
     
 ?
 

测试:

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

 

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

 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:c="http://www.springframework.org/schema/c"

 

6.4、bean的作用域

1.单例模式(Spring默认机制)(单线程使用这个,尽量使用单例!)

2.原型模式:每次从容器中get的时候,都会产生一个新对象 !(多线程使用这个!)

3.几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

 

7、Bean的自动装配(autowired)

  • 自动装配是Spring满足bean依赖的一种方式!

  • Spring会在上下文中自动寻找,并自动给bean装配属性!

 

在Spring 中有三种装配的方式

1.在xml中显示的配置

2.在java中显示配置

3.隐式的自动装配bean【重要!】

 

7.1、测试

环境搭建:一个人有两个宠物!

1、新建两个实体类,Cat Dog 都有一个叫的方法!

 public class Cat {
     public void shout(){
         System.out.println("喵~");
     }
 }
 public class Dog {
     public void shout(){
         System.out.println("wang~");
     }
 }

2、新建一个用户类 User

 package com.kuang.pojo;
 ?
 public class People {
     private Cat cat;
     private Dog dog;
     private String name;
 ?
     public String getName() {
         return name;
     }
 ?
     public void setName(String name) {
         this.name = name;
     }
 ?
     public Cat getCat() {
         return cat;
     }
 ?
     public void setCat(Cat cat) {
         this.cat = cat;
     }
 ?
     public Dog getDog() {
         return dog;
     }
 ?
     public void setDog(Dog dog) {
         this.dog = dog;
     }
 ?
     @Override
     public String toString() {
         return "People{" +
                 "cat=" + cat +
                 ", dog=" + dog +
                 ", name='" + name + '\'' +
                 '}';
     }
 }

3、编写Spring配置文件

 <?xml version="1.0" encoding="UTF-8"?>
 
 ?
     
     
   
     
        
        
        
    
 ?
 

4、测试

 @Test
 public void test(){
     ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
     People people = (People) context.getBean("people");
     people.getCat().shout();
     people.getDog().shout();
 }

 

7.2、ByName自动装配



    

7.3、ByType自动装配

 
 
 ?
 
 
 ?
 
 
     
 

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性set方法的值一致!

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

7.4、使用注解实现自动装配

jdk1.5支持的注解,Spring2.5就支持注解了!

The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.

要使用注解须知:

  1. 导入约束:context约束

  2. 配置注解的支持:http://www.mybatis.org/spring/zh/index.html

    什么是 MyBatis-Spring?

    MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。

    MyBatis-Spring 需要以下版本:

    MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
    2.0 3.5+ 5.0+ 4.0+ Java 8+
    1.3 3.4+ 3.2.2+ 2.1+ Java 6+

    如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:

     
        org.mybatis
        mybatis-spring
        2.0.2
     

    注意:SqlSessionFactory需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。

    在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。

    在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。

    SqlSessionFactory有一个唯一的必要属性:用于 JDBC 的 DataSource。这可以是任意的 DataSource 对象,它的配置方法和其它 Spring 数据库连接是一样的。

    一个常用的属性是 configLocation,它用来指定 MyBatis 的 XML 配置文件路径。它在需要修改 MyBatis 的基础配置非常有用。通常,基础配置指的是 < settings> 或 < typeAliases>元素。

    需要注意的是,这个配置文件并不需要是一个完整的 MyBatis 配置。确切地说,任何环境配置(),数据源()和 MyBatis 的事务管理器()都会被忽略。SqlSessionFactoryBean 会创建它自有的 MyBatis 环境配置(Environment),并按要求设置自定义环境的值。

    SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。

    模板可以参与到 Spring 的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用,你应该总是用 SqlSessionTemplate 来替换 MyBatis 默认的 DefaultSqlSession 实现。在同一应用程序中的不同类之间混杂使用可能会引起数据一致性的问题。

    可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。

     
      
     

    现在,这个 bean 就可以直接注入到你的 Mapper bean 中了。你需要在你的 bean 中添加一个 SqlSession 属性,就像下面这样:

     public class UserDaoImpl implements UserMapper {
     ?
      private SqlSession sqlSession;
     ?
      public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
     }
     ?
      public User getUser(String userId) {
        return sqlSession.getMapper...;
     }
     }

    按下面这样,注入 SqlSessionTemplate:

     
      
     

    整合实现一

    1、引入Spring配置文件beans.xml

     <?xml version="1.0" encoding="UTF-8"?>
     

    2、配置数据源替换mybaits的数据源

     
         
         
         
         
     

    3、配置SqlSessionFactory,关联MyBatis

     
     
         
         
         
         
     

    4、注册sqlSessionTemplate,关联sqlSessionFactory;

     
     
         
         
     

    5、增加Dao接口的实现类;私有化sqlSessionTemplate

    UserMapperImpl.java

     package com.kuang.mapper;
     ?
     import com.kuang.pojo.User;
     import org.mybatis.spring.SqlSessionTemplate;
     ?
     import java.util.List;
     ?
     public class UserMapperImpl implements UserMapper{
     ?
         //我们所有的操作,都使用sqlSession来执行,在原来,现在都使用SQLSessionTemplate;
         private SqlSessionTemplate sqlSession;
     ?
         public void setSqlSession(SqlSessionTemplate sqlSession) {
             this.sqlSession = sqlSession;
         }
     ?
         @Override
         public List selectUser() {
             UserMapper mapper = sqlSession.getMapper(UserMapper.class);
             return mapper.selectUser();
         }
     }

    6、注册bean实现

    applicationContext.xml

     <?xml version="1.0" encoding="UTF-8"?>
     
     ?
         
     ?
         
             
         
     

    7、测试

     @Test
     public void test()  {
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
         UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
         List userList = userMapper.selectUser();
         for (User user : userList) {
             System.out.println(user);
         }
     }

     

    spring-dao.xml / beans

     <?xml version="1.0" encoding="UTF-8"?>
     
     ?
         
         
             
             
             
             
         
     ?
         
         
             
             
             
             
         
     ?
         
         
             
             
         
     ?
     

     

     

    结果成功输出!现在我们的Mybatis配置文件的状态!发现都可以被Spring整合!

    mybatis-config.xml

     <?xml version="1.0" encoding="UTF-8" ?>
     
     
     
     ?
         
             
         
     ?
     

     

    整合实现二

    mybatis-spring1.2.3版以上的才有这个 .

    测试:

    1、将我们上面写的UserDaoImpl修改一下

     package com.kuang.mapper;
     import com.kuang.pojo.User;
     import org.mybatis.spring.support.SqlSessionDaoSupport;
     ?
     import java.util.List;
     ?
     public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
     ?
         @Override
         public List selectUser() {
     ?
             return getSqlSession().getMapper(UserMapper.class).selectUser();
         }
     }
     ?

    2、修改bean的配置

     
           
     

    3、测试

        @Test
         public void test()  {
             ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
             UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
             List userList = userMapper.selectUser();
             for (User user : userList) {
                 System.out.println(user);
             }
         }

    总结 : 整合到spring以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!

     

    13、声明式事务

    1、回顾事务

    1. 把一组业务当成一个业务来做:要么都成功,要么都失败!

    2. 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎!

    3. 确保完整性和一致性;

     

    事务ACID原则:

    • 原子性

    • 一致性

    • 隔离性

      • 多个业务可能操作同一个资源,防止数据损坏

    • 持久性

      • 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!

     

    2、spring中的事务管理

    • 声明式事务:AOP

    • 编程式事务:需要在代码中,进行事务的管理

     

    思考:

    为什么需要事务?

    • 如果不配置事务,可能存在数据提交不一致的情况下;

    • 如果我们不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!

    • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!

     

    使用Spring管理事务,注意头文件的约束导入 : tx

     xmlns:tx="http://www.springframework.org/schema/tx"
     ?
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd">

    事务管理器

    • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。

    • 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。

     

    JDBC事务

     
     
         
     

    配置好事务管理器后我们需要去配置事务的通知

     
     
     
         
         
         
             
             
             
             
             
         
     
     ?
     
     
         
         
     

     

    配置AOP

    导入aop的头文件!

     
     
         
         
     

     

    测试!

     

    spring事务传播特性:

    事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:

    • propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。

    • propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。

    • propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。

    • propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。

    • propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

    • propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。

    • propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作