Spring 学习记录

news/发布时间2024/6/17 2:18:00

Spring 学习记录

  • 1. Spring和SpringFrameWork
    • 1.1 广义的Spring
    • 2.1 狭义的Spring
    • 2.3 SpringFrameWork / Spring框架图
  • 2. Spring IOC容器(即上图中的Core Container)
    • 2.1 相关概念 (IOC DI 容器 组件)
    • 2.2 Spring IOC容器的作用
    • 2.3 Spring IOC容器接口和具体实现类
  • 3. Spring IOC 实践
    • 3.1 IOC / DI 一般步骤
    • 3.2 基于 XML配置 方法
      • 3.2.1 组件信息声明配置 (IOC) 和 依赖注入配置 (DI)
      • 3.2.2 IOC容器创建和使用
      • 3.2.3 组件周期方法配置
      • 3.2.4 FactoryBean的使用
    • 3.3 基于 注解配置 方法
      • 3.3.1 Spring提供的常见注解
      • 3.3.2 注解中BeanName的问题
      • 3.3.2 Autowired 和 Resourc 注解
    • 3.4 基于 配置类 方法
    • 3.5 三种方法总结
  • 4. Spring AOP
    • 4.1 AOP是什么
    • 4.2 为什么引入AOP
    • 4.3 主要应用场景
    • 4.4 Spring AOP 基于注解实现
      • 4.4.1 Spring AOP 底层技术组成
      • 4.3.2 通知增强的类型
      • 4.4.3 切点表达式
      • 4.4.4 代码示例
  • 5.Spring-tx
    • 5.1什么是Spring-tx?为什么需要Spring-tx?
    • 5.2 代码示例
    • 5.3 事务属性

1. Spring和SpringFrameWork

通常情况下,我们所说的Spring是狭义概念的Spring,即SpringFrameWork框架。

1.1 广义的Spring

广义上的 Spring 泛指以 Spring Framework 为基础的 Spring 技术栈

经过十多年的发展,Spring 已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如 Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,其中 Spring Framework 是其他子项目的基础

2.1 狭义的Spring

狭义的 Spring 特指 Spring Framework,通常我们将它称为 Spring 框架
Spring Framework(Spring框架)是一个开源的应用程序框架,由SpringSource公司开发,最初是为了解决企业级开发中各种常见问题而创建的。它提供了很多功能,例如:依赖注入(Dependency Injection)、面向切面编程(AOP)、声明式事务管理(TX)等。其主要目标是使企业级应用程序的开发变得更加简单和快速,并且Spring框架被广泛应用于Java企业开发领域。

2.3 SpringFrameWork / Spring框架图

在这里插入图片描述
在这里插入图片描述

2. Spring IOC容器(即上图中的Core Container)

2.1 相关概念 (IOC DI 容器 组件)

  • IOC:Inversion of Control(控制反转)
    主要是针对对象的创建和调用控制而言的。当应用程序需要使用一个对象时,不再是应用程序直接创建该对象,而是由 IoC 容器来创建和管理,即控制权由应用程序转移到 IoC 容器中,也就是“反转”了控制权 。这种方式基本上是通过依赖查找的方式来实现的,即 IoC 容器维护着构成应用程序的对象,并负责创建这些对象。
  • DI: Dependency Injection(依赖注入)
    组件之间传递依赖关系的过程中,将依赖关系在容器内部进行处理,这样就不必在应用程序代码中硬编码对象之间的依赖关系,实现了对象之间的解耦合。例如在A类内部需要引用B类,不需要A类的内部创建B类的对象,而是在容器内完成。在 Spring 中,DI 是通过 XML 配置文件或注解的方式实现的。它提供了三种形式的依赖注入:构造函数注入、Setter 方法注入和接口注入
  • IOC容器:IOC是是一种思想而不是某种技术 简而言之即对象不再由应用程序创建,而是由另外的独立的模块来创建,我们把这个独立的模块称为容器,由于应用了IOC思想,所以叫做IOC容器。Spring框架应用了IOC思想将对象的创建放在了独立的模块中,称为Spring IOC容器。
  • 组件:简而言之,组件是对象。但是对象不一定是组件

在这里插入图片描述

2.2 Spring IOC容器的作用

Spring 框架中的IOC容器负责创建组件、管理组件的依赖关系、存储组件,销毁组件。减少编码压力,让程序员更加专注进行业务编写。
容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。配置元数据以 XML、Java 注解或 Java 代码形式表现。它允许表达组成应用程序的组件以及这些组件之间丰富的相互依赖关系。
在这里插入图片描述
配置元数据的方式

  • XML配置方式:是Spring框架最早的配置方式之一,通过在XML文件中定义Bean及其依赖关系、Bean的作用域等信息,让Spring IoC容器来管理Bean之间的依赖关系。该方式从Spring框架的第一版开始提供支持。
  • 注解方式:从Spring 2.5版本开始提供支持,可以通过在Bean类上使用注解来代替XML配置文件中的配置信息。通过在Bean类上加上相应的注解(如@Component, @Service, @Autowired等),将Bean注册到Spring IoC容器中,这样Spring IoC容器就可以管理这些Bean之间的依赖关系。
  • Java配置类方式:从Spring 3.0版本开始提供支持,通过Java类来定义Bean、Bean之间的依赖关系和配置信息,从而代替XML配置文件的方式。Java配置类是一种使用Java编写配置信息的方式,通过@Configuration、@Bean等注解来实现Bean和依赖关系的配置。

2.3 Spring IOC容器接口和具体实现类

  • 接口BeanFactory接口提供了配置框架和基本功能,ApplicationContext接口继承自BeanFactory接口,添加了更多特定于企业的功能。
  • 实现类:以下实现类都继承了某些父类,这些父类实现了ApplicatiContext接口。
    在这里插入图片描述
    例如:ClassPathXmlApplicationContext的类继承关系如下:引用自该文章
    在这里插入图片描述

3. Spring IOC 实践

3.1 IOC / DI 一般步骤

元数据配置——容器读取配置并实例化——获取对应的组件
元数据配置:此步骤只是进行配置而不进行具体的实例化
容器读取配置并实例化组件:此步骤容器会对配置读取进而实例化组件
获取对应的组件:此步骤是获取所需要的组件
在这里插入图片描述

3.2 基于 XML配置 方法

3.2.1 组件信息声明配置 (IOC) 和 依赖注入配置 (DI)

  • 基于无参构造函数在这里插入图片描述
public class HappyComponent {//默认包含无参数构造函数public void doWork() {System.out.println("HappyComponent.doWork");}
}
...
<bean id="happyComponent" class="com.local.ioc_01.HappyComponent"/>
  • 基于有参的构造函数
    如果是基本类型,就用value。如果是引用类型,就用ref。所ref的类型要在配置文件中已经配置过,并且ref的是对应类型的id。
    在这里插入图片描述
public class UserDao {
}public class UserService {private UserDao userDao; private int age; private String name;public UserService(int age , String name ,UserDao userDao) {this.userDao = userDao;this.age = age;this.name = name;}
}
<bean id="userDao" class="com.local.ioc_01.UserDao"/>
<bean id="userService" class="com.local.ioc_01.UserService"><constructor-arg name="name" value="zzz"/><constructor-arg name="age" value="12"/><constructor-arg name="userDao" ref="userDao"/>
</bean>
  • 基于静态工厂方法(创建对象的方法是静态方法)
    注:工厂方法——在方法内部创建对象,外部访问的时候只需要访问方法就可以,类似在“工厂”内部对对象进行创建,而使用者不用关心在工厂内部发生了什么。
    factory-method: 指定静态工厂方法,注意,该方法必须是static方法。
public class ClientService {public static ClientService createInstance() {return new ClientService();}
}
<bean id="clientService" class="com.local.ioc_01.ClientService" factory-method="createInstance"/>
  • 基于实例工厂方法(创建对象的方法是非静态方法)
    factory-bean属性:指定当前容器中工厂Bean 的名称。
    factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的
public class DefaultServiceLocator {public ClientService createClientServiceInstance() {return new ClientService();}
}
<bean id="serviceLocator" class="com.local.ioc_01.DefaultServiceLocator"/>
<bean id="clientService2" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
  • 基于Setter方法依赖注入
public class MovieFinder {
}public class SimpleMovieLister {private MovieFinder movieFinder;private String movieName;public void setMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}public void setMovieName(String movieName){this.movieName = movieName;}
}
<bean id="movieFinder" class="com.local.ioc_02.MovieFinder"/>
<bean id="movieLister" class="com.local.ioc_02.SimpleMovieLister"><property name="movieFinder" ref="movieFinder"/><property name="movieName"   value="电影"/>
</bean>

3.2.2 IOC容器创建和使用

# spring-ioc-01.xml是要读取的配置文件
# getBean()中填写要创建的组件对应的id和对应的反射ClassPathXmlApplicationContext Context = new ClassPathXmlApplicationContext("spring-ioc-01.xml");
UserService userService = Context.getBean("userService", UserService.class);

3.2.3 组件周期方法配置

可以在组件类中定义方法,然后当IOC容器实例化和销毁组件对象的时候进行调用。这两个方法我们成为生命周期方法。
类似于Servlet的init/destroy方法,我们可以在周期方法完成初始化和释放资源等工作。
方法命名随意,但是要求方法必须是 public void 无形参列表

public class BeanOne {public void init(){System.out.println("init....");}public void destroy(){System.out.println("destroy....");}
}
<bean id="bean" class="com.local.ioc_03.BeanOne" init-method="init" destroy-method="destroy"/>
ClassPathXmlApplicationContext Context = new ClassPathXmlApplicationContext("spring-ioc-03.xml");
BeanOne bean = Context.getBean("bean", BeanOne.class);
Context.close();
//init....
//destroy....

3.2.4 FactoryBean的使用

FactoryBean 是接口。类实例化该接口后可以将创建复杂对象的过程存储在FactoryBean 的getObject方法中。
待定…

在这里插入代码片

3.3 基于 注解配置 方法

和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。

3.3.1 Spring提供的常见注解

@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字,在语法层面没有区别。但是为了代码的可读性,不要随意乱起。
在这里插入图片描述

  • 使用注解的组件
@Controller
public class UserController {@Autowiredprivate UserService userService;}@Service
public class UserService {@Autowiredprivate UserDao userDao;
}@Repository
public class UserDao {
}
  • xml配置文件进行扫描
基本扫描
<context:component-scan base-package="com.atguigu.components"/>排除扫描
<context:component-scan base-package="com.atguigu.components"><!-- context:exclude-filter标签:指定排除规则 --><!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 --><!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 --><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>指定扫描
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<context:component-scan base-package="com.atguigu.ioc.components" use-default-filters="false"><!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 --><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
  • 获取对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotation01.xml");
UserController bean = context.getBean(UserController.class);

3.3.2 注解中BeanName的问题

使用 XML 方式管理 bean 的时候,每个 bean 都有一个唯一标识——id 属性的值,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
默认情况:类名首字母小写就是 bean 的 id。例如:SoldierController 类对应的 bean 的 id 就是 soldierController。
还可以使用value属性指定:

@Controller(value = "tianDog")
public class SoldierController {
}

3.3.2 Autowired 和 Resourc 注解

  • AutoWired注解
    在成员变量上直接标记@Autowired注解即可。容器创建对象的时候会自动寻找对应的组件进行注入。注入流程如下:
    在这里插入图片描述
@Controller(value = "tianDog")
public class SoldierController {@Autowired@Qualifier(value = "maomiService222")// 根据面向接口编程思想,使用接口类型引入Service组件private ISoldierService soldierService;//依赖注入的时候,去寻找value值对应的注解
  • Resource注解
    @Resource注解默认根据 Bean名称装配,未指定name时,使用属性名作为name通过name找不到的话会自动启动通过类型装配。
    @Autowired注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用
    @Autowired注解是Spring提供的注解,@Resource注解是JDK扩展包中的。【高于JDK11或低于JDK8需要引入以下依赖
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version>
</dependency>
@Controller
public class UserController {/*** 1. 如果没有指定name,先根据属性名查找IoC中组件xxxService* 2. 如果没有指定name,并且属性名没有对应的组件,会根据属性类型查找* 3. 可以指定name名称查找!  @Resource(name='test') == @Autowired + @Qualifier(value='test')*/@Resourceprivate UserService UserService;
}

3.4 基于 配置类 方法

完全注解开发:Spring 完全注解配置(Fully Annotation-based Configuration)是指通过 Java配置类 代码来配置 Spring 应用程序,使用注解来替代原本在 XML 配置文件中的配置。相对于 XML 配置,完全注解配置具有更强的类型安全性和更好的可读性

  • 配置类:使用 @Configuration 注解将一个普通的类标记为 Spring 的配置类
@Configuration
@ComponentScan(basePackages = {"com.local"})
// 上述代替了使用xml文件配置
public class configuration {
}
  • IOC容器创建对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configuration.class);
UserController bean = context.getBean(UserController.class);

3.5 三种方法总结

  • XML方式配置
    在这里插入图片描述

  • XML+注解方式配置
    在这里插入图片描述

  • 完全注解方式配置
    在这里插入图片描述

4. Spring AOP

4.1 AOP是什么

AOP:Aspect Oriented Programming(面向切面编程)面向切面编程是一种思维,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

4.2 为什么引入AOP

某种程度AOP上完善和解决OOP的非核心代码冗余和不方便统一维护问题。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

4.3 主要应用场景

  1. 日志记录:在系统中记录日志是非常重要的,可以使用AOP来实现日志记录的功能,可以在方法执行前、执行后或异常抛出时记录日志。
  2. 事务处理:在数据库操作中使用事务可以保证数据的一致性,可以使用AOP来实现事务处理的功能,可以在方法开始前开启事务,在方法执行完毕后提交或回滚事务。
  3. 安全控制:在系统中包含某些需要安全控制的操作,如登录、修改密码、授权等,可以使用AOP来实现安全控制的功能。可以在方法执行前进行权限判断,如果用户没有权限,则抛出异常或转向到错误页面,以防止未经授权的访问。
  4. 性能监控:在系统运行过程中,有时需要对某些方法的性能进行监控,以找到系统的瓶颈并进行优化。可以使用AOP来实现性能监控的功能,可以在方法执行前记录时间戳,在方法执行完毕后计算方法执行时间并输出到日志中。
  5. 异常处理:系统中可能出现各种异常情况,如空指针异常、数据库连接异常等,可以使用AOP来实现异常处理的功能,在方法执行过程中,如果出现异常,则进行异常处理(如记录日志、发送邮件等)。
  6. 缓存控制:在系统中有些数据可以缓存起来以提高访问速度,可以使用AOP来实现缓存控制的功能,可以在方法执行前查询缓存中是否有数据,如果有则返回,否则执行方法并将方法返回值存入缓存中。
  7. 动态代理:AOP的实现方式之一是通过动态代理,可以代理某个类的所有方法,用于实现各种功能。

4.4 Spring AOP 基于注解实现

4.4.1 Spring AOP 底层技术组成

在这里插入图片描述

  • 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。
  • cglib:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口。
  • AspectJ:早期的AOP实现的框架,SpringAOP借用了AspectJ中的AOP注解。

4.3.2 通知增强的类型

即表示将切面中的方法切入到核心方法中的哪里去。

- 前置通知:在被代理的目标方法前执行 @Before
- 返回通知:在被代理的目标方法成功结束后执行 @After
- 异常通知:在被代理的目标方法异常结束后执行 @AfterThrowing
- 后置通知:在被代理的目标方法最终结束后执行 @AfterReturning
- 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置 @Around

4.4.3 切点表达式

  • 什么是切点表达式
    在准备好切面后,需要确定将切面切入到哪里,即切入到核心方法的哪里,切点表达式即指定说明了切入的点。
  • 切点表达式语法
  • 第一位:execution( ) 固定开头
  • 第二位:方法访问修饰符
public private 直接描述对应修饰符即可
  • 第三位:方法返回值
int String void 直接描述返回值类型
注意:特殊情况 不考虑 访问修饰符和返回值execution(* * ) 这是错误语法execution(*) == 你只要考虑返回值 或者 不考虑访问修饰符 相当于全部不考虑了
  • 第四位:指定包的地址
 固定的包: com.atguigu.api | service | dao单层的任意命名: com.atguigu.*  = com.atguigu.api  com.atguigu.dao  * = 任意一层的任意命名任意层任意命名: com.. = com.atguigu.api.erdaye com.a.a.a.a.a.a.a  ..任意层,任意命名 用在包上!注意: ..不能用作包开头   public int .. 错误语法  com..找到任何包下: *..
  • 第五位:指定类名称
固定名称: UserService
任意类名: *
部分任意: com..service.impl.*Impl
任意包任意类: *..*
  • 第六位:指定方法名称
语法和类名一致
任意访问修饰符,任意类的任意方法: * *..*.*
  • 第七位:方法参数
第七位: 方法的参数描述具体值: (String,int) != (int,String) 没有参数 ()模糊值: 任意参数 有 或者 没有 (..)  ..任意参数的意识部分具体和模糊:第一个参数是字符串的方法 (String..)最后一个参数是字符串 (..String)字符串开头,int结尾 (String..int)包含int类型(..int..)
  • 切点表达式重用
    Q:为什么要对切点表达式重用?
    A:当多个切面表达式相同时,后期进行修改维护较麻烦,例如以下:前2个和后2个的切面表达式相同,因此将切点表达式提取到同一个类中,方便重用。
@Before(value = "execution(public int *..Calculator.sub(int,int))")
..........
@AfterReturning(value = "execution(public int *..Calculator.sub(int,int))")
.........
@AfterThrowing(value = "execution(* *..*Service.*(..))")
.........
@After(value="execution(* *..*Service.*(..))")
......

Q:如何重用?如何重用后引用?

// 重用
@Component
public class PointCut {@Pointcut(value = "execution(public int *..Calculator.sub(int,int))")public void GlobalPointCut(){}@Pointcut(value = "execution(* *..*Service.*(..))")public void SecondPointCut(){}
}//引用
@Before(value = "GlobalPointCut")  //value中是方法名
public void printLogBeforeCoreOperation() {}

4.4.4 代码示例

在这里插入图片描述

//定义计算接口
public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}//接口的核心代码实现类(只实现核心代码而忽略一些打印输出和异常处理的代码)
@Component
public class CalculatorPureImpl implements Calculator {  @Overridepublic int add(int i, int j) {return i + j;}  @Overridepublic int sub(int i, int j) {return i - j;}@Overridepublic int mul(int i, int j) {return i * j;}@Overridepublic int div(int i, int j) {return i / j;}
}//重用切面表达式
@Component
public class MyPointCut {@Pointcut(value = "execution(* service.impl.*.*(..))")public void pointCutOne(){}
}//切面
@Component
@Aspect
public class LogAdvice {@Before("PointCut.MyPointCut.pointCutOne()")public void start(){System.out.println("start");}@After("PointCut.MyPointCut.pointCutOne()")public void end(){System.out.println("end");}@AfterThrowing("PointCut.MyPointCut.pointCutOne()")public void error(){System.out.println("error");}
}//配置类扫描和开启aspectj注解
@Configuration
@ComponentScan({"service","advice","config"}) //扫描
@EnableAspectJAutoProxy //开启aspectj注解
public class JavaConfig {
}//测试
@SpringJUnitConfig(value = JavaConfig.class)
public class SpringAopTest {@Autowiredprivate Calculator calculator;@Testpublic void test1(){int res=calculator.add(1,1);System.out.println(res);}
}
//输出
start
end
2

5.Spring-tx

5.1什么是Spring-tx?为什么需要Spring-tx?

  • Spring-tx是Spring框架支持以声明性的方式管理事务,而不是编程式的方式。将事务的控制和业务逻辑分离开来,提高代码的可读性和可维护性
try {// 开启事务:关闭事务的自动提交conn.setAutoCommit(false);// 核心操作// 业务代码// 提交事务conn.commit();  
}catch(Exception e){  // 回滚事务conn.rollBack();
}finally{ // 释放数据库连接conn.close();
}
  • 编程式事务:手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚。
  • 声明式事务:使用注解或 XML 配置的方式来控制事务的提交和回滚。开发者只需要添加配置即可, 具体事务的实现由第三方框架实现,避免我们直接进行事务操作。

5.2 代码示例

在这里插入图片描述

//jdbc.properties
atguigu.url=jdbc:mysql://localhost:3306/fruitdb
atguigu.driver=com.mysql.cj.jdbc.Driver
atguigu.username=root
atguigu.password=123456//javaconfig
@Configuration
@ComponentScan({"Dao","Service"})
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement //开启事务注解的支持
public class JavaConfig {@Value("${atguigu.driver}")private String driver;@Value("${atguigu.url}")private String url;@Value("${atguigu.username}")private String username;@Value("${atguigu.password}")private String password;//druid连接池@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Bean//jdbcTemplatepublic JdbcTemplate jdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//使用事务管理器 //事务管理器需要数据库连接信息datasource@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}
}//FruitDao
@Repository
public class FruitDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void updatePriceByName(String name,Integer price){String sql = "update t_fruit set price = ? where fname = ? ;";int rows = jdbcTemplate.update(sql, price,name);}public void updateRemarkByName(String name,String remark){String sql = "update t_fruit set remark= ? where fname = ? ;";jdbcTemplate.update(sql,remark,name);}
}//FruitService 
@Service
public class FruitService {@Autowiredprivate FruitDao fruitDao;@Transactional //添加事务注解public void changeInfo(){fruitDao.updatePriceByName("苹果",30);int i=1/0; //这里会报错 那么整个事务将会回滚,2次修改信息都将失败 如果没有事务 那么第一次将修改成功而第二次失败fruitDao.updateRemarkByName("苹果","ok");}
}

上述代码在FruitService的方法中添加了Transactionnal注解,该注解可以作用与类和方法上,作用于类上说明对类内的方法都生效,作用于方法则只对方法生效。

5.3 事务属性

  • 只读
    在Transactionnal注解中设置属性readOnly属性为True,默认值为False
    在这里插入图片描述
@Transactional(readOnly = true)
  • 超时时间
    程序运行过程中因为某些原因卡住占用资源,设置超时时间,事务运行的时间超过超过设置的超时时间则回滚,释放资源。通过timeout属性设置。默认值是-1,即无限。
    在这里插入图片描述
@Transactional(timeout = 3)
  • 事务异常
    关于异常的分类可以参考此文章-异常分类总结
    默认只针对运行时异常回滚,编译时异常不回滚
    rollbackForClassName:指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
    noRollbackForClassName:指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
public class FruitService {@Autowiredprivate FruitDao fruitDao;@Transactional(noRollbackFor = ArithmeticException.class) //添加事务注解 发生该异常时不回滚public void changeInfo(){fruitDao.updatePriceByName("苹果",30);int i=1/0; //这里会报错 但是设置为不回滚 所以第一条修改成功,但是第二条修改失败fruitDao.updateRemarkByName("苹果","ok");}
}
  • 隔离级别
    数据库事务的隔离级别是指在多个事务并发执行时,数据库系统为了保证数据一致性所遵循的规定。常见的隔离级别包括:
  1. 读未提交(Read Uncommitted):事务可以读取未被提交的数据,容易产生脏读、不可重复读和幻读等问题。实现简单但不太安全,一般不用。
  2. 读已提交(Read Committed):事务只能读取已经提交的数据,可以避免脏读问题,但可能引发不可重复读和幻读。
  3. 可重复读(Repeatable Read):在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读的问题。
  4. 串行化(Serializable):最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕之后才能执行另一个事务。可以避免以上所有问题,但效率较低,不适用于高并发场景。
@Transactional(isolation = Isolation.REPEATABLE_READ)
  • 事务传播
    在这里插入图片描述
    @Transactional 注解通过 propagation 属性设置事务的传播行为。它的默认值是
Propagation propagation() default Propagation.REQUIRED;

在这里插入图片描述

//jdbc.properties
atguigu.url=jdbc:mysql://localhost:3306/fruitdb
atguigu.driver=com.mysql.cj.jdbc.Driver
atguigu.username=root
atguigu.password=123456//javaconfig
@Configuration
@ComponentScan({"Dao","Service"})
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement //开启事务注解的支持
public class JavaConfig {@Value("${atguigu.driver}")private String driver;@Value("${atguigu.url}")private String url;@Value("${atguigu.username}")private String username;@Value("${atguigu.password}")private String password;//druid连接池@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Bean//jdbcTemplatepublic JdbcTemplate jdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//使用事务管理器 //事务管理器需要数据库连接信息datasource@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}
}//FruitDao
@Repository
public class FruitDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void updatePriceByName(String name,Integer price){String sql = "update t_fruit set price = ? where fname = ? ;";int rows = jdbcTemplate.update(sql, price,name);}public void updateRemarkByName(String name,String remark){String sql = "update t_fruit set remark= ? where fname = ? ;";jdbcTemplate.update(sql,remark,name);}
}//FruitService
@Service
public class FruitService {@Autowiredprivate FruitDao fruitDao;@Transactional(noRollbackFor = ArithmeticException.class,propagation = Propagation.REQUIRES_NEW) //添加事务注解 发生该异常时不回滚 并且修改默认传播public void changePrice(){fruitDao.updatePriceByName("香蕉",50);int i=1/0; //这里会报错 但是设置了不回滚}@Transactionalpublic void changeRemark(){fruitDao.updateRemarkByName("苹果","good");}
}//TopService 整合的Service
@Service
public class TopService {@Autowiredprivate FruitService fruitService;@Transactionalpublic void changeInfo(){fruitService.changePrice();fruitService.changeRemark();}
}//测试
@Test
public void test(){topService.changeInfo();
}结果:父事务默认的传播行为,changePrice方法中修改了默认的传播方法,并且遇到运行错误时不回滚。
那么changePrice方法则忽略父方法中的传播行为,独立创建事务。
结果是成功修改了price而没有修改remark。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/ICZi/9263.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

Linux零拷贝技术浅谈

Linux零拷贝不是什么新知识点了&#xff0c;网上资料一大堆&#xff0c;这是2021年我要在公司做一次分享&#xff0c;就写了这篇文章&#xff0c;图片很多是来源于网络。 一、零拷贝的由来和定义 1. 基本概念 内核态&#xff1a;Ring0级别&#xff0c;运行在内核空间中&…

神经网络系列---感知机(Neuron)

文章目录 感知机(Neuron)感知机(Neuron)的决策函数可以表示为&#xff1a;感知机(Neuron)的学习算法主要包括以下步骤&#xff1a;感知机可以实现逻辑运算中的AND、OR、NOT和异或(XOR)运算。 感知机(Neuron) 感知机(Neuron)是一种简单而有效的二分类算法&#xff0c;用于将输入…

Docker(运维工具)—— 学习笔记

快速构建、运行、管理应用的工具 一、安装docker 参考Install Docker Engine on Ubuntu | Docker Docs 二、快速入门 1、镜像和容器 docker镜像可以做到忽略操作系统的差异&#xff0c;跨平台运行&#xff0c;忽略安装的差异 当我们利用Docker安装应用时&#xff0c;Dock…

【k8s】-- 查询 pod 磁盘容量

命令&#xff1a;kubectl get pvc -n 你的namespace --context上下文命名 -o wide 举例&#xff1a;kubectl get pvc -n my-bigdata --contextprod-6 -o wide

【BUG 记录】史诗级 BUG - MYSQL 删库删表却没有备份如何恢复数据

【BUG 记录】史诗级 BUG - MYSQL 删库删表却没有备份如何恢复数据 1. 问题描述2. 解决方案&#xff08;binlog&#xff09;2.1 构造测试环境2.2 查看 MySQL 环境是否开启 binlog2.3 查看所有的 binlog 日志记录2.4 查看当前正在使用的是哪一个 binlog 文件2.5 查看此时的 binlo…

轻量级模型,重量级性能,TinyLlama、LiteLlama小模型火起来了,针对特定领域较小的语言模型是否与较大的模型同样有效?

轻量级模型&#xff0c;重量级性能&#xff0c;TinyLlama、LiteLlama小模型火起来了&#xff0c;针对特定领域较小的语言模型是否与较大的模型同样有效? 当大家都在研究大模型&#xff08;LLM&#xff09;参数规模达到百亿甚至千亿级别的同时&#xff0c;小巧且兼具高性能的小…

06 vim工具

目录 概念模式基本操作配置 1. 概念 vim是一个历史悠久的,多模式的编辑器&#xff0c;是vi的升级版。和ide不同&#xff0c;编辑器仅能编写文本&#xff0c;不能运行代码&#xff0c;现阶段的代码编译的各个过程会分开按步骤执行 2. 模式 vim有很多种模式&#xff0c;想要编…

【学习总结】什么是DoS和DDoS

[Q&A] 什么是DoS DoS 是 “Denial of Service”&#xff08;拒绝服务&#xff09;的缩写&#xff0c;它是一种网络攻击方式&#xff0c;其目的是使目标计算机或网络资源无法为合法用户提供正常的服务。通过向目标系统发送大量请求、消耗其带宽、处理器或内存等资源&#…

使用空闲电脑免费搭建一个私人的网盘

如果你也有一台空闲电脑&#xff0c;可以使用它来搭建一个私人的网盘。 这里使用的是飞梦云网盘&#xff1b; 服务端&#xff1a;下载 服务器文件使用hash校验进行储存&#xff0c;实现重复上传的文件秒传功能。 Fuse4Ui&#xff08;虚拟分区工具&#xff09;&#xff1a;下…

高性能API云原生网关 APISIX安装与配置指南

Apache APISIX是Apache软件基金会下的顶级项目&#xff0c;由API7.ai开发并捐赠。它是一个高性能的云原生API网关&#xff0c;具有动态、实时等特点。 APISIX网关可作为所有业务的流量入口&#xff0c;为用户提供了丰富的功能&#xff0c;包括动态路由、动态上游、动态证书、A…

18 SpringMVC实战

18 SpringMVC实战 1. 课程介绍2. Spring Task定时任务1. 课程介绍 2. Spring Task定时任务 package com.imooc.reader.task

BlackWidow靶场

kali&#xff1a;192.168.223.128 主机发现 nmap -sP 192.168.223.0/24 目标IP:192.168.223.153 端口扫描 nmap -sV -p- -A 192.168.223.153 22/tcp open ssh OpenSSH 7.9p1 Debian 10deb10u2 (protocol 2.0) 80/tcp open http Apache httpd 2.4.38 ((Deb…

Window系统禅道BUG管理系统安装配置并实现公网远程访问

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

[NPUCTF2020]ezinclude ---不会编程的崽

做完这题&#xff0c;又get到一个新的知识点。上界面 源代码里有线索 secret是秘密值&#xff0c;name与pass应该是可以控制的变量。抓个包看看 发送与请求有hash值&#xff0c;没猜错应该是用来验证的。拿去爆破了&#xff0c;啥也没爆破出来。先传参 右边的hash值改变了。猜想…

小苯的IDE括号问题(CD) -----牛客小白月赛87(双链表)

C题&#xff1a;C-小苯的IDE括号问题&#xff08;easy&#xff09;_牛客小白月赛87 (nowcoder.com) D题&#xff1a; D-小苯的IDE括号问题&#xff08;hard&#xff09;_牛客小白月赛87 (nowcoder.com) C题代码&#xff1a; #include<bits/stdc.h>using namespace std…

百度云AI

百度云AI概述 Face腾讯优图科大讯飞 百度人脸识别基于深度学习的人脸识别方案&#xff0c;准确识别图片中的人脸信息&#xff0c;提供如下功能&#xff1a; 人脸检测&#xff1a;精准定位图中人脸&#xff0c;获得眼、口、鼻等72个关键点位置&#xff0c;分析性别、年龄、表…

武器大师——操作符详解(上)

目录 一、操作符的分类 二、二进制和进制转换 2.1.二进制与十进制的互相转化 2.1.1 二进制转十进制 2.1.2 十进制转二进制 ​编辑 2.2.二进制转8进制和16进制 2.2.1 转8进制 2.2.2 转16进制 三、原码、反码、补码 四、移位操作符 4.1.左移操作符&#xff08;<…

#LLM入门|Prompt#2.2_ AI 应用开发的范式_Language_Models,the_Chat_Format_and_Tokens

在本章中&#xff0c;我们将和您分享大型语言模型&#xff08;LLM&#xff09;的工作原理、训练方式以及分词器&#xff08;tokenizer&#xff09;等细节对 LLM 输出的影响。 我们还将介绍 LLM 的提问范式&#xff08;chat format&#xff09;&#xff0c;这是一种指定系统消息…

F2图例封装 - Bar

基于vue3 和 F2 3.5.0 <template><div :style"{minHeight: ${height}px,width: 100% }" ref"container"><canvas v-show"showChart" :id"chartId" class"chart-canval"></canvas><empty-box v-…

容器镜像详解

1. 镜像组成 一个标准的OCI容器镜像由index, manifest, config, image layers这几个部分组成。 以docker镜像为例&#xff0c;下载的镜像文件保存在/var/lib/docker/目录下面 image/overlay2子目录下面保存着镜像相关的一些元数据 在下面的介绍主要以nginx:latest镜像为例子…
推荐文章