2-Spring

news2024/12/25 9:16:48

2-Spring

文章目录

  • 2-Spring
  • 项目源码地址
  • Spring概述
    • Spring特点(优点)
    • Spring相关学习网站
    • 基于Maven的Spring框架导入
    • Spring的组成及拓展
  • Spring-IOC--原型理解
    • IOC-原型--示例
      • 开发示例-常规
      • 开发示例-Set函数(IOC原型)
      • 开发示例-对比思考
    • IOC-本质--概念
    • IOC-实现--Spring中以IOC方式管理bean
      • 示例--HelloWorld
      • 理解
    • IOC-修改--Spring实现IOC
  • Spring-IOC--IOC Container
    • bean--创建
      • 无参构造创建
      • 带参构造创建
    • bean--配置
      • 别名配置
      • import-多xml配置文件管理
    • DI-依赖注入-基本
      • 注入方式
      • 注入方式-Set注入详解-N种常见类型数据注入
      • 注入方式-p标签、c标签注入
    • Bean--作用域
    • Bean--自动装配--Autowire
      • 案例
      • 常规case:手动装配
      • Spring-自动装配-XML:byName
      • Spring-自动装配-XML:byType
      • Spring-自动装配-注解-@Autowired
      • Spring-自动装配-注解-@Qualifier
      • Spring-自动装配-注解-@Resource
      • Spring-三种注解方法:@Autowired、@Qualifier、@Resource总结
      • Spring-自动装配-注解-@Component、@Value、@scope
      • Spring-自动装配-XML与注解的对比
      • Java-自动装配-注解-@Configuration、@ComponentScan
  • AOP
    • 代理模式理解
    • AOP基本概念
      • 什么是AOP?
      • Aop在Spring中的相关概念
    • Spring中实现AOP
      • 示例中通用的代码
      • XML配置--通过Spring API来实现
      • XML配置--通过自定义类来实现
      • 注解--通过自定义类来实现
  • Spring事务
    • 事务四大特性:acid
    • Spring中的事务
      • **编程式事务管理**
      • 声明式事务管理
    • Spring声明式事务处理
      • 导入约束
      • 定义事务管理器
      • 配置事务通知
      • spring事务传播特性
      • 配置AOP织入事务
      • 测试代码

项目源码地址

GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程Java_Framework_Spring

Spring概述

Spring特点(优点)

  • Spring是一个开源免费的框架,容器
  • Spring是一个轻量级的框架,非侵入式的
  • 控制反转IOC,面向切面AOP【IOC和AOP是Spring学习的重点】
  • 对事务支持,对框架支持

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器【框架】

Spring相关学习网站

  • 中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/core.html#beans

  • 官方文档:https://spring.io/projects/spring-framework#learn

image-20231113161012523

  • 源码下载:https://repo.spring.io/ui/native/milestone/org/springframework/spring/

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

基于Maven的Spring框架导入

  • 访问:https://mvnrepository.com/
  • 搜索:Spring

image-20231113161529095

  • xml配置导入
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.0.13</version>
</dependency>

导入该依赖,通过依赖传递性,会自动导入:spring-aop、spring-beans、spring-context、spring-core、spring-expression、spring-web

Spring的组成及拓展

七大组成模块

模块组成

模块作用
Spring Core核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开
Spring ContextSpring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能
Spring AOP通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中
Spring DAOJDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构
Spring ORMSpring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构
Spring WebWeb 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作
Spring MVCMVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI

Spring拓展:Spring Boot 和 Spring Cloud

Spring BootSpring Cloud
是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务基于Spring Boot实现的
专注于快速、方便集成的单个微服务个体关注全局的服务治理框架
使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系
起承上启下的作用如果要学习SpringCloud必须要学习SpringBoot

Spring-IOC–原型理解

IOC-原型–示例

开发示例-常规

三层结构:

  • 底层源码,Dao:接口、实现

  • 业务端,Service:业务接口、业务实现

  • 客户端,Client:调用

源码实现

image-20231114104459154

  • 底层源码:UserDao接口
public interface UserDao {
   public void getUser();
}
  • 底层源码:UserDao实现
public class UserDaoImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Dao获取用户数据");
  }
}
  • 业务端:UserService接口
public interface UserService {
   public void getUser();
}
  • 业务端:UserService实现
public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}
  • 用户端:测试
public class UserTest {
    @Test
    public void test(){
        UserService service = new UserServiceImpl();
        service.getUser();
    }
}

若增加一个源码实现

  • UserSql
public interface UserSql {
   public void getUser();
}
public class UserSqlImpl implements UserSql {
   @Override
   public void getUser() {
       System.out.println("Sql获取用户数据");
  }
}
  • 业务端:UserService实现代码更改
public class UserServiceImpl implements UserService {
    // 原内容
	private UserDao userDao = new UserDaoImpl();
   	// 修改后的内容
    private UserDao userDao = new UserSqlImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

针对常规开发模式,每增加一个源码实现,都需要对服务端实现的代码进行更改,非常麻烦。代码耦合性太高

如何解决?利用Set函数

开发示例-Set函数(IOC原型)

保持其他内容不变,修改服务端实现类的代码内容

public class UserServiceImpl implements UserService {
   private UserDao userDao;
   
    // 利用set实现
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

客户端代码实现

@Test
public void test(){
   
    UserServiceImpl service = new UserServiceImpl();
   	// Dao实现
    service.setUserDao( new UserDaoMySqlImpl() );
   	service.getUser();
   	
    //Sql实现
   	service.setUserDao( new UserSqlImpl() );
   	service.getUser();
}

可以看到,针对新的源码实现,不再需要修改业务端逻辑,仅是在客户端,通过传入不同的业务端实现对象,即可完成更改

开发示例-对比思考

常规IOC原型
对象创建主动权在程序对象创建主动权在调用者
对象是写死的,更改实现对象,就需要更改业务端代码对象是通过接口动态接收的,调用者给什么,就实现什么

IOC-本质–概念

  • IoC(Inversion of Control,控制反转) 是一种设计思想,DI(Dependency Injection,依赖注入) 是实现IoC的一种方法

    • 在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
  • 没有IoC的程序中 , 我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,实现解耦。

image-20231113224431882

IOC-实现–Spring中以IOC方式管理bean

示例–HelloWorld

源码准备

image-20231114103303148

  • HelloWorld.java
package com.learn.Hello;

public class HelloWorld {
    private String name;

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

    public void show(){
        System.out.println("Hello,"+ name );
    }
}
  • 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--bean就是java对象 , 由Spring创建和管理-->
    <bean id="hello" class="com.learn.Hello.HelloWorld">
        <property name="name" value="Spring"/>
    </bean>

</beans>
  • HelloWorldTest.java
import com.learn.Hello.HelloWorld;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloWorldTest {
    @Test
    public void test(){
        //解析beans.xml文件, 生成管理相应的Bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean : 参数即为spring配置文件中bean的id .
        HelloWorld hello = (HelloWorld) context.getBean("hello");
        hello.show();
    }
}

理解

思考

Hello 对象是谁创建的?由Spring创建的
Hello 对象的属性是怎么设置的?由Spring容器设置的(根据set方法)

IOC理解

  • 这个过程就叫控制反转
    • 控制 : 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
    • 反转:程序本身不创建对象 , 而变成被动的接收对象
  • 依赖注入
    • 依赖:相关属性信息配置在xml文件中
    • 注入:通过set方法,由Spring读取xml文件,并创建对象

IOC-修改–Spring实现IOC

  • 新建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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!--底层源码实现-->
   <bean id="MysqlImpl" class="com.learn.dao.UserMySqlImpl"/>
   <bean id="DaoImpl" class="com.learn.dao.UserDaoImpl"/>

   <!--业务端代码实现-->
   <bean id="ServiceImpl" class="com.learn.service.UserServiceImpl">
       <!--注意: 这里的name并不是属性, 而是UserServiceImpl实现类里面setUserDao方法中set后面的那部分, 其中首字母要小写-->
       <!--该方法的参数是引用另外一个bean, 这里不能用value,而是用ref-->
       <property name="userDao" ref="OracleImpl"/>
   </bean>

</beans>
  • 修改客户端的测试代码
// ===== 原内容 ===== 
@Test
public void test(){
   
    UserServiceImpl service = new UserServiceImpl();
   	// Dao实现
    service.setUserDao( new UserDaoMySqlImpl() );
   	service.getUser();
   	
    //Sql实现
   	service.setUserDao( new UserSqlImpl() );
   	service.getUser();
}

// ===== 修改后内容 ===== 
@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
   serviceImpl.getUser();
}
  • 后续所有的操作均不需要去改动业务端,统一由xml配置文件修改即可

Spring-IOC–IOC Container

bean–创建

无参构造创建

无参构造,属性的写入,本质是set方式注入

public class User {

   private String name;

   public User() {
       System.out.println("user无参构造方法");
  }

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

   public void show(){
       System.out.println("name="+ name );
  }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="user" class="com.kuang.pojo.User">
       <property name="name" value="kuangshen"/>
   </bean>

</beans>
@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //在执行getBean的时候, user已经创建好了, 通过无参构造
   User user = (User) context.getBean("user");
   //调用对象的方法 .
   user.show();
}

带参构造创建

带参构造,属性的写入,本质是构造器方式注入

public class UserT {

   private String name;

   public UserT(String name) {
       this.name = name;
  }

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

   public void show(){
       System.out.println("name="+ name );
  }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 第一种根据index参数下标设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <!-- index指构造方法 , 下标从0开始 -->
       <constructor-arg index="0" value="kuangshen2"/>
    </bean>

    <!-- 第二种根据参数名字设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <!-- name指参数名 -->
       <constructor-arg name="name" value="kuangshen2"/>
    </bean>
    
    <!-- 第三种根据参数类型设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <constructor-arg type="java.lang.String" value="kuangshen2"/>
    </bean>
    
</beans>
  • 第三种方法使用较为限制。当多个属性具有相同的类型,就没法用了
    • type,基本数据类型,就写:int、double…
    • type,引用数据类型就按照上边示例来写就行
@Test
public void testT(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   // 在配置文件加载的时候。其中管理的对象都已经初始化了!
   UserT user = (UserT) context.getBean("userT");
   user.show();
}

bean–配置

别名配置

alias标签配置

<!--设置别名:在获取Bean的时候可以使用别名获取,原名依旧可用-->
<alias name="userT" alias="userNew"/>

bean标签中的name属性配置

<!--bean就是java对象,由Spring创建和管理-->

<!--
   id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
   如果配置id,又配置了name,那么name是别名
   name可以设置多个别名,可以用逗号,分号,空格隔开
   如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;

class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>

import-多xml配置文件管理

<!--在主配置文件中,引入其他配置文件-->
<import resource="{path}/beans.xml"/>

DI-依赖注入-基本

依赖注入(Dependency Injection,DI)

  • 依赖 : 指Bean对象的创建依赖于容器.
  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配.

注入方式

注入方式解释
Set注入针对无参构造的bean
构造器注入针对带参构造的bean
p标签注入本质还是set注入,需要有无参构造方法
c标签注入本质是构造器注入,需要有带参构造方法

注入方式-Set注入详解-N种常见类型数据注入

  • 要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写

  • 如果属性是boolean类型 , 没有set方法 , 是 is.【有疑问?IDEA 2023创建出来的boolean属性有set方法,但是没有get方法】

常见属性类型的set方式注入

package com.kuang.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 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;
 
     // set方法
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAddress(Address address) {
         this.address = address;
    }
 
     public void setBooks(String[] books) {
         this.books = books;
    }
 
     public void setHobbys(List<String> hobbys) {
         this.hobbys = hobbys;
    }
 
     public void setCard(Map<String, String> card) {
         this.card = card;
    }
 
     public void setGames(Set<String> games) {
         this.games = games;
    }
 
     public void setWife(String wife) {
         this.wife = wife;
    }
 
     public void setInfo(Properties info) {
         this.info = info;
    }
 
     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n爱好:"+hobbys);
         System.out.println("card:"+card);
         System.out.println("games:"+games);
         System.out.println("wife:"+wife);
         System.out.println("info:"+info);
    }
 }

常量注入

<bean id="student" class="com.kuang.pojo.Student">
	<property name="name" value="小明"/>
</bean>

bean注入

  • 常规ref引入
 <bean id="addr" class="com.kuang.pojo.Address">
     <property name="address" value="重庆"/>
 </bean>
 
 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
 </bean>
  • inner bean引入
    • 需要要求该inner bean 不会被其他地方引用
    • 即该inner bean随着outer bean的创建而创建
<bean id="outer" class="...">
    <!-- instead of using a reference to a target bean, simply define the target bean inline -->
    <property name="target">
        <bean class="com.example.Person"> <!-- this is the inner bean -->
            <property name="name" value="Fiona Apple"/>
            <property name="age" value="25"/>
        </bean>
    </property>
</bean>

数组注入

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
     <property name="books">
         <array>
             <value>西游记</value>
             <value>红楼梦</value>
             <value>水浒传</value>
         </array>
     </property>
 </bean>

List注入

 <property name="hobbys">
     <list>
         <value>听歌</value>
         <value>看电影</value>
         <value>爬山</value>
     </list>
 </property>

Map注入

 <property name="card">
     <map>
         <entry key="中国邮政" value="456456456465456"/>
         <entry key="建设" value="1456682255511"/>
     </map>
 </property>

集合set注入

 <property name="games">
     <set>
         <value>LOL</value>
         <value>BOB</value>
         <value>COC</value>
     </set>
 </property>

Null注入

<property name="wife"><null/></property>

Properties注入

 <property name="info">
     <props>
         <prop key="学号">20190604</prop>
         <prop key="性别"></prop>
         <prop key="姓名">小明</prop>
     </props>
 </property>

注入方式-p标签、c标签注入

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

    <!--需要在头部导入p标签约束:上述倒数第三行-->
    <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--需要在头部导入c标签约束:上述倒数第三行-->
    <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

Bean–作用域

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。

简单地讲,bean就是由IoC容器初始化、装配及管理的对象。

类别说明
singleton(默认)在Spring IOC容器中仅存一个Bean实例,以单例方式存在
prototype每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XXXBean()
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session同一个Http Session共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext环境

Singleton

  • 创建容器时就同时自动创建一个bean对象
  • 不管是否调用,实例已经存在了
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

Prototype

  • 创建容器的时候没有初始化
  • 当获取bean的时候才会去创建一个对象
 <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
  或者
 <bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

Request

  • 每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

Session

  • 在一个HTTP Session中,一个bean定义对应一个实例
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

Bean–自动装配–Autowire

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

不需要手动给与属性,Sping会在上下文中自动寻找,并自动给bean装配属性

案例

  • 一个人,有名字和两个宠物,分别是猫和狗,都会叫:猫会miao,狗会wang
  • 分析:
    • 3个bean:狗、猫、人
    • 狗的bean:“叫”方法
    • 猫的bean:“叫“方法
    • 人的bean:三个属性,名字、狗、猫
public class Cat {
   public void shout() {
       System.out.println("miao~");
  }
}
public class Dog {
   public void shout() {
       System.out.println("wang~");
  }
}
package com.learn.Hello;

public class People {
    private Cat cat;
    private Dog dog;

    private String 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;
    }

    public String getName() {
        return name;
    }

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

常规case:手动装配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--猫-->
    <bean id="cat" class="com.learn.Hello.Cat"/>
   
    <!--狗-->
    <bean id="dog" class="com.learn.Hello.Dog"/>

    <!--人-->
    <bean id="People" class="com.learn.Hello.People">
    	<property name="name" value="张三"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>
    </bean>

</beans>

Spring-自动装配-XML:byName

会自动在上下文中查找id跟自己属性值一样的bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--猫-->
    <bean id="cat" class="com.learn.Hello.Cat"/>
	</bean>
   
    <!--狗-->
    <bean id="dog" class="com.learn.Hello.Dog"/>
    </bean>

    <!--人-->
    <bean id="People" class="com.learn.Hello.People" autowire="byName">
    	<property name="name" value="张三"/>
    </bean>

</beans>
  • 将cat的id改为catXXX,报错

Spring-自动装配-XML:byType

会根据属性的类型,自动去上下文中找对应属性的bean,这就要求属性全局唯一,不然idea会报错,不让用该种装配方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--猫-->
    <bean id="cat" class="com.learn.Hello.Cat">
	</bean>
   
    <!--狗-->
    <bean id="dog" class="com.learn.Hello.Dog">
    </bean>

    <!--人-->
    <bean id="People" class="com.learn.Hello.People" autowire="byType">
    	<property name="name" value="张三"/>
    </bean>

</beans>
  • case1:再注册一个cat对象,bean id取名为cat2,报错
  • case2:将cat和dog的id删除掉,运行,正常【因为是通过Type进行自动装配的,不影响】

Spring-自动装配-注解-@Autowired

该方式可以不需要bean中有set方法

准备

  • 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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <!--正常写入bean信息-->
    
</beans>

测试

package com.learn.Hello;

import org.springframework.beans.factory.annotation.Autowired;

public class People {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

    private String name;

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <!--猫-->
    <bean id="cat" class="com.learn.Hello.Cat"/>

    <!--狗-->
    <bean id="dog" class="com.learn.Hello.Dog"/>

    <!--人-->
    <!--人的属性默认给为null-->
    <bean id="people" class="com.learn.Hello.People"/>

</beans>
  • 删除掉People类中的set方法,加入注解,测试,依旧成功

@Autowired参数

public class People {
    @Autowired(required=false)
    private Cat cat;
}
  • required=false,即对象可以为null;该参数默认为true,即注解的属性不可以为null

Spring-自动装配-注解-@Qualifier

  • @Autowired是根据类型(Type)自动装配的,当根据类型无法完成装配时,加上@Qualifier则可以根据byName的方式自动装配
  • @Qualifier不能单独使用,需要和@Autowired配套使用
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
package com.learn.Hello;

import org.springframework.beans.factory.annotation.Autowired;

public class People {
    @Autowired()
    @Qualifier(value = "cat2")
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog2")
    private Dog dog;

    private String name;

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

    public String getName() {
        return name;
    }

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

Spring-自动装配-注解-@Resource

不是Spring框架的注解,而是Java自带的注解

@Resource如有参数指定name属性,先按该属性进行byName方式查找装配;其次再进行默认的byName方式进行装配

  • 如果以上都不成功,则按byType的方式自动装配
  • 都不成功,则报异常
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User"/>
public class User {
   //如果允许对象为null,设置required = false, 默认为true
   @Resource(name = "cat2")
   private Cat cat;
   @Resource
   private Dog dog;
   private String str;
}

补充

  • jdk的版本影响注解@Resource的使用

  • 解决方法1:使用jdk8开发

  • 解决方法2:在maven中的pom.xml从新导入一个javax.annotation的jar包

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.2</version>
</dependency>

Spring-三种注解方法:@Autowired、@Qualifier、@Resource总结

注解方法解释
@Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在
如果要允许null 值,可以设置它的required属性为false:@Autowired(required=false)
@Qualifier按照name装配:配合@Autowired使用
当@Autowired无法按照类型装配的时候,配合@Qualifier,按照name装配
@Resource默认按照名称进行装配,名称可以通过name属性进行指定
如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找
如果注解写在setter方法上默认取属性名进行装配
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配

Spring-自动装配-注解-@Component、@Value、@scope

从基于xml文件的bean标签实现依赖注入,到通过@Component注解形式实现注入

准备工作

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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--指定注解扫描包-->
	<context:component-scan base-package="com.kuang.pojo"/>
    
    <context:annotation-config/>

</beans>
  • AOP包的引入:

    <!-- 该引入,可以引入spring有关的好几个包,包括AOP -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.0.13</version>
    </dependency>
    

image-20231115171251990

指定包下编写类,并加入注解

@Component("user")  // 相当于配置文件中 <bean id="user" class="com.spring.learn.User"/>
@Scope("prototype") // 相当于配置文件中 <bean id="user" class="com.spring.learn.User" scope="prototype"/>
public class User {
   @Value("张三")		// 写在字段上:相当于配置文件中 <property name="name" value="张三"/>
   public String name;
   public int age;
   
   @Value(18)	// 写在set方法上:相当于配置文件中 <property name="age" value="张三"/>
   public void setAge(int age) {
       this.age = age;
  }
}

测试

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}

@Component衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能跟@Component都一样

注解应用场景
@Controller在Controller层进行注入时使用的注解
@Service在Service层进行注入时使用的注解
@Repository在Dao层进行注入时使用的注解

Spring-自动装配-XML与注解的对比

XML注解
可以适用任何场景 ,结构清晰,维护方便注解只能对特定的类生效,开发简单方便
  • 推荐使用:XML管理bean,注解完成属性注入(写在字段上或写在方法上的注解)
  • 当使用XML管理bean的时候,就不用扫描了,扫描是为了扫描类上的注解

Java-自动装配-注解-@Configuration、@ComponentScan

JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能

从原先的xml文件配置依赖注入,到通过Java类配置依赖注入

实体类

@Component  // 将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
   public String name = "dog";
}

Config包:起到beans.xml文件的作用

@Configuration  //代表这是一个配置类
@ComponentScan("com.learn.Dog") // 代表要扫描Dog包下的类,带有注解的类将被放进Spring中管理
public class MyConfig {
   @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
   public Dog getDog(){
       return new Dog();
  }
}

@ComponentScan 和 @Configuration 一般配合一起使用

  • 如果没有@ComponentScan,会默认扫描@Configuration所注解的类所在的包

  • 但为什么要配合使用?

    如果类中用了@Controller,@Repository,@Service, @Component四大注解标识之一了,那么如果不加上@ComponentScan,Spring就不会自动扫描类上的四大注解中的任何一个,那么四大注解下的类就不会被Spring扫描到,更不会装入Spring容器中,因此配置的四大注解就失去了作用

测试

@Test
public void test2(){
   ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
   Dog dog = (Dog) applicationContext.getBean("getDog");
   System.out.println(dog.name);
}

AOP

代理模式理解

AOP的底层实现就是动态代理,学习AOP之前先了解动态代理

参考文章:https://blog.csdn.net/qq_45445505/article/details/134038354

AOP基本概念

先写下来,不求甚解了,边学边回顾吧

什么是AOP?

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Aop在Spring中的相关概念

作用:提供声明式事务;允许用户自定义切面

相关名词

名词解释
横切关注点跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。
如日志 , 安全 , 缓存 , 事务等等 …
切面(ASPECT)横切关注点 被模块化 的特殊对象。即,它是一个类
通知(Advice)切面必须要完成的工作。即,它是类中的一个方法
目标(Target)被通知对象
代理(Proxy)向目标对象应用通知之后创建的对象
切入点(PointCut)切面通知 执行的 “地点”的定义
连接点(JointPoint)与切入点匹配的执行点

image-20231116164845909

Spring中支持的5种Advice类型

通知类型连接点实现接口
前置通知方法前org.springframework.aop.MethodBeforeAdvice
后置通知方法后org.springframework.aop.AfterReturningAdvice
环绕通知方法前后org.springframework.aop.MethodInterceptor
异常抛出通知方法抛出异常org.springframework.aop.ThrowsAdvice
引介通知类中增加新的方法属性org.springframework.aop.IntroductionInterceptor

Spring中实现AOP

示例中通用的代码

业务层

package GSF.Example.Service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void search();
}
package GSF.Example.Service;

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("执行User的add方法");
    }

    @Override
    public void delete() {
        System.out.println("执行User的delete方法");
    }

    @Override
    public void update() {
        System.out.println("执行User的update方法");
    }
    
    @Override
    public void search() {
        System.out.println("执行User的search方法");
    }
}

测试

package GSF.Example.Test;

import GSF.Example.Service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void Test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
//        userService.delete();
//        userService.update();
//        userService.search();
    }
}

XML配置–通过Spring API来实现

项目名称:

  • Java_Framework_Spring
  • AOP_1_Xml_SpringAPI

前置通知示例

package GSF.Example.Log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class LogBeforeMethod implements MethodBeforeAdvice {
    /***
     *
     * @param method 要执行的目标对象(UserServiceImpl)的方法
     * @param args 被调用的方法的参数
     * @param target 目标对象(UserServiceImpl)
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("AOP前置通知:" + "在" + target.getClass().getName() + "的" + method.getName() + "方法调用前执行。目标对象-方法-参数,都可以获取到");
    }
}

后置通知

package GSF.Example.Log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class LogAfterMethod implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("AOP后置通知:" + "在" + target.getClass().getName() + "的" + method.getName() + "方法调用后执行。目标对象-方法-参数,都可以获取到");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!--  注册bean  -->
    <bean id="userService" class="GSF.Example.Service.UserServiceImpl" />
    <bean id="logBefore" class="GSF.Example.Log.LogBeforeMethod" />
    <bean id="logAfter" class="GSF.Example.Log.LogAfterMethod"/>

	<!-- Aop的设置-->
    <aop:config>
		<!-- 切入点-->
        <aop:pointcut id="pointcut" expression="execution(* GSF.Example.Service.UserServiceImpl.*(..))"/>
		<!-- 执行前置通知-->
        <aop:advisor advice-ref="logBefore" pointcut-ref="pointcut" />
        <aop:advisor advice-ref="logAfter" pointcut-ref="pointcut" />
    </aop:config>
</beans>

XML配置–通过自定义类来实现

项目名称:

  • Java_Framework_Spring
  • AOP_2_Xml_CustomClass
package GSF.Example.Log;

public class CustomLogClass {
    public void before(){
        System.out.println("---------基于XML自定义类方式实现,前置通知:方法执行前---------");
    }

    public void after(){
        System.out.println("---------基于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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!--  注册bean  -->
    <bean id="userService" class="GSF.Example.Service.UserServiceImpl" />
    <bean id="customLogClass" class="GSF.Example.Log.CustomLogClass" />

	<!--Aop的设置-->
    <aop:config>
		<!-- 切入点-->
        <aop:aspect ref="customLogClass">
            <aop:pointcut id="pointcut" expression="execution(* GSF.Example.Service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut" />
        </aop:aspect>
    </aop:config>
</beans>

注解–通过自定义类来实现

项目名称:

  • Java_Framework_Spring
  • AOP_3_Xml_Annotation
package GSF.Example.Log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationClass {
    @Before("execution(* GSF.Example.Service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("---------基于注解方式实现,前置通知:方法执行前---------");
    }

    @After("execution(* GSF.Example.Service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("---------基于注解方式实现,后置通知:方法执行后---------");
    }

    @Around("execution(* GSF.Example.Service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable{
        System.out.println("环绕通知:环绕前");
        System.out.println(jp.getSignature());

        // 执行目标方法
        Object proceed = jp.proceed();
        System.out.println(proceed);

        System.out.println("环绕通知:环绕后");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- 注册bean  -->
    <bean id="userService" class="GSF.Example.Service.UserServiceImpl" />
    <bean id="annotationPointcut" class="GSF.Example.Log.AnnotationClass" />
    
    <!-- 自动代理 -->
    <aop:aspectj-autoproxy/>

</beans>

Spring事务

事务四大特性:acid

特性解释
原子性(atomicity)事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
一致性(consistency)一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
隔离性(isolation)可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
持久性(durability)事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中

Spring中的事务

  • Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。

  • Spring支持编程式事务管理和声明式的事务管理

编程式事务管理

  • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

声明式事务管理

  • 一般情况下比编程式事务好用。
  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
  • 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。

Spring声明式事务处理

项目名称:

  • Java_Framework_Spring
  • Transaction_Spring_Mybatis

导入约束

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
  • tx有关的

定义事务管理器

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

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

<!-- JDBC事务 -->
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
</bean>

配置事务通知

<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       <!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
       <tx:method name="add" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="search*" propagation="REQUIRED"/>
       <tx:method name="get" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>

spring事务传播特性

  • 事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播
  • spring支持的事务传播行为
参数含义
propagation_requierd(默认)如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择
propagation_supports支持当前事务,如果没有当前事务,就以非事务方法执行
propagation_mandatory使用当前事务,如果没有当前事务,就抛出异常
propagation_required_new新建事务,如果当前存在事务,把当前事务挂起
propagation_not_supported以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
propagation_never以非事务方式执行操作,如果当前事务存在则抛出异常
propagation_nested如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作

配置AOP织入事务

<!--配置aop织入事务-->
<aop:config>
   <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
   <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

测试代码

  • 人为制造错误:写错deletes
<delete id="deleteUser" parameterType="int">
    deletes from learn_mybatis.user where id=#{id};
</delete>
  • UserDaoImpl多个方法放一起
package GSF.Example.Dao;

import GSF.Example.Pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;
import java.util.Map;

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{

    @Override
    public User getUserById(int id) {

        User user = new User(id, "测试事务", "123235");
        UserDao mapper = getSqlSession().getMapper(UserDao.class);

        mapper.addUser(user);
        mapper.deleteUser(id);

        return mapper.getUserById(id);
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserDao.class).addUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserDao.class).deleteUser(id);
    }

}
  • 测试代码
package GSF.Example.Dao;

import GSF.Example.Pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {
    @Test
    public void TestTransaction(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserDao userDaoImpl = (UserDao) context.getBean("userDaoImpl");

        User userById = userDaoImpl.getUserById(28);
        System.out.println(userById);
    }
}
  • 结果分析
    • 未开启事务,新增数据成功,并没有删除数据
    • 开启事务,新增数据失败

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【热】如何实现el-table列宽随内容长度自适应最小宽度

非常火急火燎的来写这篇博客&#xff01;&#xff01;因为自己一开始想实现这个效果时在网上查了很久查了很多资料和博客都没有找到能有效达到效果的方法&#xff0c;要么就是别人说有效但是我这里会报错而且难以解决。最后终于被我自己给摸索出来了&#xff01; 应用场景 很…

AI+无代码助力企业供应链优化

内容来自演讲&#xff1a;潘峰 | 预见明日科技&#xff08;北京&#xff09;有限公司 | CEO 摘要 本文介绍了企业供应链中的挑战和解决方案。文章指出&#xff0c;供应链成本占企业经营成本的大部分&#xff0c;且存在供给端和需求端的高度不确定性。为应对这种不确定性&…

Openwrt源码下载出现“The remote end hung up unexpected”

最近项目原因需要下载openwrt21.02版本源码&#xff0c;花费了很多时间&#xff0c;找到正确方法后&#xff0c;发现可以节省很多时间&#xff0c;记录下过程&#xff0c;方便自己&#xff0c;可能方便他人。 一.问题阐述 openwrt21.02下载链接如下&#xff1a; git clone -…

Uncaught ReferenceError: jQuery is not defined解决方法

当我在写java的Maven项目时&#xff0c;出现了这样的一个报错信息&#xff1a; 我一直找代码&#xff0c;抓包&#xff0c;调试&#xff0c;比对代码 jQuery未定义就是指JS的导包没有导进来&#xff01;&#xff01;&#xff01;&#xff01; 导进来就运行正常啦

12.字符串拼接【2023.12.4】

1.问题描述 我们在编程过程中经常会遇到把不同字符串拼接在一起的情况&#xff0c;从而更直观地展示给用户我们所要表达的信息。本题将给出两个字符串&#xff0c;请依次将这两个字符串拼接在一起。 2.解决思路 用字符串拼接符 进行连接两个字符串 3.代码实现 str1input(…

SpringBoot中MyBatis-Flex的集成和使用

一、MyBatis-Flex 是什么​ MyBatis-Flex是一个基于MyBatis的数据访问框架&#xff0c;专门为Flex应用程序而设计的。它提供了一种灵活而高效的方式来处理Flex应用程序中的数据访问&#xff0c;可以轻松地连接到各种数据源&#xff0c;并提供了一些方便的工具和功能&#xff0c…

2023.12.6-12.11 黑马知行教育项目实战,访问咨询意向线索主题

目录 简单介绍: 一.项目背景介绍 二.项目架构介绍 三.项目内容 3.1访问和咨询分析主题: 3.1.1 表与表之间的关联 3.1.2访问咨询主题需求汇总:最终需在ADS层制作六张表 3.1.3 访问咨询DWS大宽表建表与导入数据 3.2意向线索主题需求分析 3.2.1意向线索主题需求汇总:最终需在…

最新科研成果:在钻石中存储多比特数据,实现25GB数据密度

近日&#xff0c;纽约城市大学&#xff08;CUNY&#xff09;的研究人员已经成功地利用钻石原子结构中的小型氮缺陷作为“颜色中心”来写入数据进行存储&#xff08;然后是检索&#xff09;。这项发表在《自然纳米技术》上的技术允许通过将数据编码为多个光频率&#xff08;即颜…

[GFCTF 2021]文件查看器

文章目录 前置知识可调用对象数组对方法的调用GC回收机制phar修改签名 解题步骤 前置知识 可调用对象数组对方法的调用 我们先来看下面源码 <?phperror_reporting(0);class User{public $username;public $password;public function check(){if($this->username"…

架构LAMP

目录 1.什么是LAMP 2.LAMP组成及作用 3.搭建Apache httpd服务 4.编译安装mysqld 服务 5.编译安装PHP 解析环境 6.安装论坛 1.什么是LAMP LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务…

Threejs项目实战之一:汽车外观换肤效果三维展示

目录 最终效果1 创建项目2 安装插件3 编写代码3.1 准备工作3.2 代码编写3.2.1 在template标签中构建html页面3.2.2 在style标签中构建页面样式文件3.2.3 在script标签中编写js代码 最终效果 先看下最终实现的效果 接下来&#xff0c;我们就从创建项目开始&#xff0c;一步一步…

三天精通Selenium Web 自动化 - 测试框架(一)

1 框架结构雏形 返回 新建的一个java project&#xff0c;项目名为autotest,创建如下结构 图1 框架结构雏形 base&#xff1a;里面有个基类 &#xff08;BaseParpare.java&#xff09;&#xff0c;这个类的主要作用是启动&#xff08;启动浏览器使用了TetsNG的BeforeClass&am…

P4 Qt基础控件——工具按钮toolButton(上)

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f33a;本篇简介 &#xff1a;这一章我们学一…

披荆斩棘的「矿区无人驾驶」,能否真正打开千亿级市场?

随着2022年备受瞩目的台泥句容矿无人驾驶运输项目硬核落地&#xff0c;以及相关科技公司开放该矿24小时无人矿卡生产运营直播以证明其项目并非在演示&#xff0c;2023年全国开启了大规模矿区无人驾驶商业化落地&#xff0c;堪称矿区无人驾驶元年。虽然我国矿区无人驾驶市场渗透…

【C语言】数据结构——小堆实例探究

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 导读&#xff1a; 我们在前面学习了单链表和顺序表&#xff0c;以及栈和队列。 今天我们来学习小堆。 关注博主或是订阅专栏&a…

ArkUI组件

目录 一、概述 声明式UI 应用模型 二、常用组件 1、Image&#xff1a;图片展示组件 示例 配置控制授权申请 2、Text&#xff1a;文本显示组件 示例 3、TextInput&#xff1a;文本输入组件 示例 4、Button&#xff1a;按钮组件 5、Slider&#xff1a;滑动条组件 …

【日志技术】附Logback入门教程

文章目录 日志概论日志的体系Logback快速入门日志配置文件配置日志级别 日志概论 什么是日志&#xff1f;其实可以通过下面几个问题来了解的。 系统系统能记住某些数据被谁操作&#xff0c;比如被谁删除了&#xff1f;想分析用户浏览系统的具体情况&#xff0c;比如挖掘用户的…

常州经开区大学生音乐节——常州首届校园乐队比赛

2023年12月9日下午&#xff0c;由江苏省文化馆指导、常州经开区社会事业局主办、常州柒号文化传播有限公司承办、百吉琴行协办的青春制“燥”大学生音乐节——常州首届校园乐队比赛&#xff0c;在常州经开区文化活动中心顺利举办。 常州经开区社会事业局副局长 方姣 为本次比赛…

CPU、内存与硬盘及IO操作

目录 1、概念简介 1.1 CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09; 1.2 硬盘&#xff08;Hard Disk Drive&#xff09; 1.3 内存&#xff08;Memory&#xff09; 2、计算机程序在进行io读写操作时&#xff0c;这三者的功能和实现原理 1、概…

使用Gson完成java对象的序列化和反序列化

一、前言&#xff1a;json是什么&#xff1f;&#xff0c;Gson是什么&#xff1f; 1.JSON&#xff08;javaScript Object Notation&#xff09; 是一种轻量级的数据交换格式。易于人阅读和编写&#xff0c;同时也易于机器解析和生成。 2.Gson 是Google提供的用来在java对象…