Spring 學習記錄

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.pswp.cn/news/711527.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/711527.shtml
英文地址,請注明出處:http://en.pswp.cn/news/711527.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

flask 數據庫遷移報錯 Error: No such command ‘db‘.

初學FLASK&#xff0c;使用pycharm的terminal 啟動&#xff0c;實現數據庫遷移 文件結構 項目啟動文件不在一級目錄pycharm>terminal啟動 由于自己初入 python flask 很多東西并不懂&#xff0c;只能依葫蘆畫瓢&#xff0c;使用如下命令,輸入完第一行命令執行沒有任何錯誤…

素數合集(C語言版)

目錄 判斷素數函數 題目 素數個數 素數求和 最大的素數

微信小程序 ---- 慕尚花坊 購物車

購物車 01. 購物車-封裝購物車接口 API 思路分析&#xff1a; 為了方便后續進行購物車模塊的開發&#xff0c;我們在這一節將購物車所有的接口封裝成接口 API 函數 落地代碼&#xff1a; import http from ../utils/http/*** description 獲取購物車列表數據* returns Pro…

Vue ElementUI 修改消息提示框樣式—messageBox 的大小

在窄屏模式下&#xff08;移動端或pda&#xff09;&#xff0c;提示框的寬度太寬&#xff0c;會出現顯示不完全的問題。 應當如何修改 ElementUI 的樣式呢&#xff1f; open() {this.$confirm(window.vm.$i18n.t("tips.conLogOut"),window.vm.$i18n.t("tips.tip…

11-Linux部署集群準備

Linux部署集群準備 介紹 在前面&#xff0c;我們所學習安裝的軟件&#xff0c;都是以單機模式運行的。 后續&#xff0c;我們將要學習大數據相關的軟件部署&#xff0c;所以后續我們所安裝的軟件服務&#xff0c;大多數都是以集群化&#xff08;多臺服務器共同工作&#xff…

【機器學習實戰1】泰坦尼克號:災難中的機器學習(一)數據預處理

&#x1f338;博主主頁&#xff1a;釉色清風&#x1f338;文章專欄&#xff1a;機器學習實戰&#x1f338;今日語錄&#xff1a;不要一直責怪過去的自己&#xff0c;她曾經站在霧里也很迷茫。 &#x1f33c;實戰項目簡介 本次項目是kaggle上的一個入門比賽 &#xff1a;Titani…

錨索測力計數據處理與分析:MCU自動測量單元的應用

錨索測力計作為一種重要的工程監測工具&#xff0c;在橋梁、大壩、隧道等結構物的健康監測中發揮著日益重要的作用。如何高效、準確地處理和分析&#xff0c;錨索測力計所獲取的數據成為了工程師們面臨的重要問題。近年來&#xff0c;隨著微控制器(MCU)技術的快速發展&#xff…

Python繪制實時空氣質量地圖

我們將使用 Google Colab 中的 Python 創建包含實時空氣質量數據的交互式地圖。 ??簡介 如果有人想查看地圖上各個傳感器的空氣質量分布情況,以檢查特定位置的空氣質量數據,該怎么辦?我接下來將解決這個問題。我們重點關注基于名為 PurpleAir 的密集空氣質量網絡來識別我們…

spring: HandlerInterceptor

文章目錄 一、什么是HandlerInterceptor二、應用示例 一、什么是HandlerInterceptor HandlerInterceptor 是 Spring 框架中的一個接口&#xff0c;用于攔截處理程序執行。在 Spring MVC 中&#xff0c;你可以使用 HandlerInterceptor 來在處理程序執行前、執行后或渲染視圖之前…

51-n皇后(回溯算法)

題目 按照國際象棋的規則&#xff0c;皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。 n 皇后問題 研究的是如何將 n 個皇后放置在 nn 的棋盤上&#xff0c;并且使皇后彼此之間不能相互攻擊。 給你一個整數 n &#xff0c;返回所有不同的 n 皇后問題 的解決方案。 每一…

前端開發項目必備神器之node工具整理

前言&#xff1a; 在我們開發項目中&#xff0c;node是我們必備的工具&#xff0c;在為了適應各種不同的開發需求的同時&#xff0c;node也有很多好用的插件提供給我們&#xff0c;這里整理個人的使用分享給大家&#xff01; 一、node相關 1、node官方網站&#xff0c;可以安裝…

模擬算法題練習(二)(DNA序列修正、無盡的石頭)

&#xff08;一、DNA序列修正&#xff09; 問題描述 在生物學中&#xff0c;DNA序列的相似性常被用來研究物種間的親緣關系。現在我們有兩條 DNA序列&#xff0c;每條序列由 A、C、G、T 四種字符組成&#xff0c;長度相同。但是現在我們記錄的 DNA序列存在錯誤&#xff0c;為了…

ubuntu基礎操作(1)-個人筆記

搜狗輸入法Linux官網-首頁搜狗輸入法for linux—支持全拼、簡拼、模糊音、云輸入、皮膚、中英混輸https://pinyin.sogou.com/linux 1.關閉sudo密碼&#xff1a; 終端&#xff08;ctrl alt t&#xff09;輸入 sudo visudo 打開visudo 找到 %sudo ALL(ALL:ALL) ALL 這一行…

羊大師分享,羊奶奶有哪些對健康有益的喝法?

羊大師分享&#xff0c;羊奶奶有哪些對健康有益的喝法&#xff1f; 羊奶奶有多種對健康有益的喝法&#xff0c;以下是一些建議&#xff1a; 直接飲用&#xff1a;將羊奶直接煮沸后飲用&#xff0c;可以保留羊奶中的營養成分&#xff0c;為身體提供全面的滋養。羊奶的豐富蛋白質…

代碼隨想錄算法訓練營第二十八天補|93.復原IP地址 ● 78.子集 ● 90.子集II

組合問題&#xff1a;集合內元素的組合&#xff0c;不同集合內元素的組合 分割問題&#xff1a;本質還是組合問題&#xff0c;注意一下如何分割字符串 回溯模板偽代碼 void backtracking(參數) {if (終止條件) {存放結果;return;}for (選擇&#xff1a;本層集合中元素&#xf…

Softmax

Softmax函數是一種在機器學習和深度學習中廣泛使用的激活函數&#xff0c;特別是在處理多分類問題時。它將一個含任意實數的向量轉換成一個概率分布&#xff0c;其中每個元素的值代表了屬于對應類別的概率。Softmax函數的輸出是所有可能類別的概率分布&#xff0c;這些概率的總…

【六袆 - MySQL】MySQL 5.5及更高版本中,InnoDB是新表的默認存儲引擎;

InnoDB 這是一個MySQL組件&#xff0c;結合了高性能和事務處理能力&#xff0c;以確保可靠性、健壯性和并發訪問。它體現了ACID設計哲學。它作為一個存儲引擎存在&#xff0c;處理使用ENGINEINNODB子句創建的或修改的表。請參閱第14章“InnoDB存儲引擎”以獲取有關架構細節和管…

【解決】虛幻導入FBX模型不是一個整體

問題&#xff1a; 現在有一個汽車的fbx模型&#xff0c;導入虛幻引擎&#xff0c;導入后變成了很多汽車零件模型。 解決&#xff1a; 把“合并網格體”勾選上&#xff0c;解決問題。

移動端app如何設計測試用例?

&#x1f345; 視頻學習&#xff1a;文末有免費的配套視頻可觀看 &#x1f345; 關注公眾號【互聯網雜貨鋪】&#xff0c;回復 1 &#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 1、用戶界面測試 布局和元素 驗證所 有UI元素&#xff08;如…

C語言拼接字符串操作

代碼解法不唯一&#xff0c;請在評論區留下你的實現方式和想法&#xff0c;我會將好的解法更新到文章中&#xff01;&#xff01; 要拼接 “字符串1” 和 “字符串2” &#xff0c;可以使用字符串連接操作。在C語言中&#xff0c;您可以使用strcat函數來將兩個字符串連接起來。…