Java教程

Spring学习笔记

本文主要是介绍Spring学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、简介

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的、非入侵式的框架
  • 控制反转((IOC),面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

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

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.14</version>
</dependency>

2、IOC本质

  • 控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有lOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,Dl)。

3、XML创建实体对象

3.1 创建实体类Hello

package pojo;

// 只有无参构造函数
public class Hello {

    private String str;
    
    /*
        public Hello(String name){
            this.str = name;
        }
    */

    public String getStr() {
        return str;
    }

    public void setStr( String str ) {
        this.str = str;
    }

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

3.2 Spring配置文件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
                           https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 无参构造 -->
    <bean id="hello" class="pojo.Hello">
        <!-- value放基本类型 -->
        <property name="str" value="Spring"/>
    </bean>
    <bean id="hello2" class="pojo.Hello2">
        <!-- ref放Spring容器中已经创建好的对象 -->
        <property name="hel" ref="hello"/>
    </bean>

    <!-- 有参构造 -->
    <!-- 第一种,下标赋值 -->
    <bean id="user" class="com. kuang.pojo.User">
        <constructor-arg index="0" value="狂神说Java" />
    </bean>
    <!-- 第二种方式:通过类型创建,不建议使用! -->
    <bean id="user" class="com. kuang.pojo.user">
        <constructor-arg type="java.lang.String" value="ginjiang"/>
    </bean>
    <!-- 第三种,直接通过参数名来设置,推荐 -->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg name="name" value="秦疆"/>
    </bean>

</beans>
  • 编写完成后记得配置应用程序上下文

3.3 测试运行

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Hello;

public class MyTest {

    @Test
    public void Test() {
        // 获取Spring的上下文对象!
        ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
        // 我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
        Hello hello = (Hello) context.getBean( "hello" );
        System.out.println( hello.toString() );
        
        //输出:Hello{str='Spring'}
    }
}

4、Spring配置

4.1 别名

  • 别名和原名都能够取到对象
<!-- Beans.xml中 -->
<!-- 方式1 -->
<alias name="user" alias="userNew" />
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
//	以下两种均可
Hello hello = (Hello) context.getBean( "user" );
Hello hello = (Hello) context.getBean( "userNew" );

4.2 Bean的配置

<!--
 id : bean的唯一标识符,也就是相当于我们学的对象名
 class : bean对象所对应的全限定名:包名+类型
 name :也是别名,而且name可以同时取多个别名,空格、逗号、分号都能做分隔
-->
<bean id="userT" c1ass="com.kuang.pojo.userT" name="user2 u2,u3;u4">
    <property name="name" value="西部开源"/>
</bean>

4.3 import

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

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中。

我们可以利用import将所有人的beans.xml合并为一个总的!

<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

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

正式的总配置文件名为applicationContext.xml

5、依赖注入

5.1 构造器注入

见3.2 Spring配置文件Beans.xml

5.2 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;
}
<bean id="student" class="com.kuang.pojo.Student">
    <!-- 第一种,普通值注入, value -->
    <property name="name" value="xx"/>

    <!-- 第二种,Bean注入,ref -->
    <property name="address" ref="address" />

    <!-- 数组 -->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>水浒传</value>
            <value>三国演义</value>
        </array>
    </property>

    <!-- List -->
    <property name="hobbys">
        <list>
            <value>听歌</value>
            <value>敲代码</value>
            <value>看电影</value>
        </list>
    </property>

    <!-- Map -->
    <property name="card">
        <map>
            <entry key="身份证" value="111111222222223333"/>
            <entry key="银行卡" value="1321231312312313123"/>
        </map>
    </property>
    
    <!-- Set -->
    <property name="games">
        <set>
            <value>LOL</value>
            <value>coc</value>
            <value>BOB</value>
        </set>
    </property>

    <!-- null -->
    <property name="wife">
        <nu11/>
    </property>
    <!-- 或者 -->
    <property name="wife" value="" />

    <!-- Properties -->
    <property name="info">
        <props>
            <prop key="driver">xxx</prop>
            <prop key="ur1">xxx</prop>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
</bean>

5.3 拓展方式注入

5.3.1 p命名空间注入

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

    <bean id="bar" class="x.y.Bar"/>
    
    <!-- p命名空问注入,可以直接注入属性的值: property -->
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/mydb"
        p:username="root"
        p:password="masterkaoli"
        p:test-ref="bar"  />

</beans>
  • 注意导入schema:xmlns:p="http://www.springframework.org/schema/p"

5.3.2 C命名空间注入

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

    <bean id="bar" class="x.y.Bar"/>
    <bean id="baz" class="x.y.Baz"/>

    <!-- 传统声明 -->
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
        <constructor-arg value="foo@bar.com"/>
    </bean>

    <!-- c命名空间声明 -->
    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>

</beans>
  • 注意导入schema:xmlns:c="http://www.springframework.org/schema/c"

5.4 Bean的作用域

image-20220126033255989

  • 单例模式 Singleton(Spring默认机制)

    <bean id="user2" class="pojo.user" c:age="18" scope="singleton" />
    
  • 原型模式 Prototype :每次从容器中getBean的时候,都会产生一个新对象!

    <bean id="user2" class="pojo.user" c:age="18" scope="prototype" />
    
  • 其余的request、session、application只能在Web开发中使用到。

6、Bean的自动装配

  • 自动装配是 Spring 满足 bean 依赖的一种方式!
  • Spring 会在上下文中自动寻找,并自动给 bean 装配属性!
  • 在 Spring 中有三种装配的方式
    • 在 XML 中显式配置
    • 在 Java 中显式配置
    • 隐式的自动装配 bean
<!-- 传统注入 -->
<beans>
    <bean id="cat" class="pojo.cat" />
    <bean id="dog" class="pojo.Dog" />
    <bean id="people" class="com.kuang.pojo.people">
        <property name="name" value="xxxx"/>
        <property name="dog" ref="dog" />
        <property name="cat" ref="cat"/>
    </bean>
</beans>

6.1 ByName自动装配

<beans>
    <bean id="cat" class="pojo.cat" />
    <bean id="dog" class="pojo.Dog" />
    
    <!-- byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id -->
    <bean id="people" class="com.kuang.pojo.people" autowire="byName">
        <property name="name" value="xxxx"/>
    </bean>
</beans>

6.2 ByType自动装配

<beans>
    <bean class="pojo.cat" />
    <bean class="pojo.Dog" />
    
    <!-- byType:会自动在容器上下文中查找,和自己对象属性类型(class)相同的bean -->
    <bean id="people" class="com.kuang.pojo.people" autowire="byType">
        <property name="name" value="xxxx"/>
    </bean>
</beans>

小结:

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

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

6.3 使用注解实现自动装配

使用注解须知:

  1. 导入约束

  2. 配置注解的支持:<context:annotation-config/>

    <?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/>
    
     <beans>
            <bean>...</bean>
        </beans>
    </beans>
    

6.3.1 @Autowired

直接在属性上使用!也可以在set方式上使用!
使用@Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性Type在 Spring 容器中存在,且符合名字byName!

<beans>
    <bean id="cat11" class="pojo.cat"/>
    <bean id="cat111" class="pojo.cat" />
    <bean id="dog22" class="pojo.Dog" />
    <bean id="dog222" class="pojo.Dog" />
    <bean id="people" class="pojo.People" />
</beans>
public class People {
    
    @Autowired
    private cat cat;
    
    //@Autowired无法实现时,要配合@qualifier(value="")来针对某一个bean进行装配
    @Autowired
    @Qualifier(value="dog222")
    private Dog dog;
    
    private string name;
}

6.3.2 @Resource

public class People {
    @Resource(name = "cat11")
    private cat cat;
    
    @Resource
    private Dog dog;
}

@Resource 和 @Autowired 的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired 先通过byType的方式实现,后通过byName,而且必须要求这个对象存在!【常用】
  • @Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】

小结:

  • @Autowired 先byType,如果同类型个数大于1,再byName。

  • dog只注册了一个的时候,dog的id可以随便取都能自动装配相当于byType。当dog注册了多个时,只能绑定id和person属性名一样的bean相当于byName,如果多个都没有对应的id就报错

  • 如果 @Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx") 去配置 @Autowired 的使用,指定一个唯一的bean对象注入!

    这个value对应的是bean的id,相当于byName。

7、使用注解开发

在 Spring 4 之后,要使用注解开发。必须要保证 aop 的包导入了!

使用注解需要导入 context 约束,增加注解的支持。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           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="pojo"/>
    <context:annotation-config/>

</beans>

7.1 常用注解

7.1.1 @Autowired

  • 通过类型、名字,自动装配
  • 如果 @Autowired 不能唯一装配上属性,则需要通过 @Qualifier( value = "xxx" ) 指定唯一bean

7.1.2 @Resource

  • 通过名字、类型,自动装配

7.1.3 @Nullable

  • 字段标记了这个注解,说明这个字段可以为null

7.1.4 @Component

  • 组件,放在类上,说明这个类被 Spring 管理了,成为Bean。
//等价于:<bean id="user" class="pojo.user"/>
@Component
public class User {

    public string name;

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

7.1.5 @Value

  • @Value( ) 放在属性或set方法上均可。
@component
public class User {
    
    //相当于 <property name="name" value="kuangshen" />
    @Value( "kuangshen2")
    public string name;
    
    public void setName( String name ) {
        this.name = name;
    }
}

7.1.6 @Scope

@component
//确定作用域:单例或原型
@scope("prototype")
public class User {
    
    public string name;
    
    @Value( "kuangshen2")
    public void setName( String name ) {
        this.name = name;
    }
}

7.2 衍生的注解

  • @Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层!

    • dao【@Repository】
    • service【@Service】
    • controller【@Controller】

    这四个注解功能都是一样的,都是代表将某个类注册到 Spring 容器中,装配Bean。

8、使用 Java 的方式(注解)配置 Spring

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

JavaConfig 是 Spring 的一个子项目,在 Spring 4 之后,它成为了一个核心功能

package config;

import pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

// 这个也会由Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration代表这是一个配置类,就和我们之前看的applicationContext.xml一样
@configuration	//相当于<beans>
@ComponentScan( "pojo" )	//扫描某个包下的所有@Component
@Import(AppConfig2.class)
public class AppConfig {
    // 注册一个bean ,就相当于我们之前写的一个<bean>标签
    // 这个方法的名字,就相当于bean标签中的id属性
    // 这个方法的返回值,就相当于bean标签中的class属性 
    @Bean
    public User user() {
        return new User();
    }
}
  • 测试
public class MyTest {
    public static void main(string[] args) {
        // 如果完全使用了配置类方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器
        // 通过配置类的class对象加载!
        Applicationcontext context = new
            AnnotationConfigApplicationContext(Appconfig.class);
        User user = (user) context.getBean("user");
        System.out.println(user.getName());
    }
}

9、代理模式

9.1 静态代理

  • 代理对象和真实对象都有共同的接口
  • 客户直接通过代理对象直接调用方法
  • 在代理类中静态扩展代码

image-20220130015452263

9.2 动态代理

  • 动态代理和静态代理角色是一样的。
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 —— JDK 动态代理
    • 基于类 —— cglib
    • Java字节码实现 —— Javassist

需要了解两个类: Proxy:代理 Invocationhandler:调用处理程序

//等我们会用这个类,自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private object target;
    
    public void setTarget(object target) {
        this.target = target;
    }
    
    //生成得到代理类
    public object getProxy(){
        return Proxy.newProxyInstance(this.getclass().getclassLoader(),
                                      target.getclass().getInterfaces(), this);
    }
    
    //处理代理实例,并返回结果:
    public object invoke(0bject proxy,Method method,object[] args) throws Throwable {
        log(method.getName());
        object result = method.invoke(target, args);
        return result;
    }
    public void log(string msg){
        system.out.println("执行了" + msg + "方法");
    }
}
public class client {
    public static void main( string[ ] args) {
        //真实角色 (实现类)
        UserServiceImpl userService = new UserServiceImpl();
        //创建代理生成类的实例
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userservice); //设置要代理的对象
        //代理角色 (动态生成代理类)
        UserService proxy = (UserService) pih.getProxy();
        proxy.query();
    }
}

动态代理相对于静态代理的好处:

无需编写代理类:对于静态代理,每个类都要写对应的代理类,会多出许多冗余的类;而动态代理,仅需通过一个代理生成类,动态生成对应类的对应代理对象,减少了代码量。

10、AOP

10.1 图解AOP

  • 什么叫面向切面编程?这就是:

image-20220130015123041

10.2 Spring 实现 AOP

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>

10.2.1 使用原生 Spring API

<!-- 注册bean -->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>

<!-- com.kuang.log.beforeLog 里面实现了 MethodBeforeAdvice 接口的 before 方法 -->
<bean id="beforeLog" class="com.kuang.log.Log"/>

<!-- com.kuang.log.afterLog 里面实现了 AfterReturningAdvice 接口的 afterReturning 方法 -->
<bean id="afterLog" class="com.kuang.log.AfterLog"/>

<!-- 方式一:使用原生Spring API接口 -->
<!-- 配置aop:需要导入aop的约束 -->
<aop:config>
    <!-- 切入点: expression:表达式,execution(要执行的位置!* * ***) -->
    <aop:pointcut id="pointcut" expression="execution(* com.kuang. service.UserServiceImpl.*(..))"/>
    <!-- 执行环绕增加! -->
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />
</aop:config>

10.2.2 自定义类实现

<!-- applicationContext.xml -->

<bean id="diy" class="com.kuang.diy.DiyPointCut" />
<aop:config>
    <!-- 自定义切面, ref要引用的类 -->
    <aop:aspect ref="diy" >
        <!-- 切入点 -->
        <aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
        <!-- 通知 -->
        <aop:before method="before" pointcut-ref="point" />
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>

10.2.3 注解实现AOP

<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut" />
<!-- 开启注解支持! -->
<aop:aspectj-autoproxy />
//方式三:使用注解方式实现AOP
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;

@Aspect //标注这个类是一个切面
public class AnnotationPointcut {

    @Before( "execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void before(){
        system.out.println( "=======方法执行前======" );
    }

    @After( "execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void after(){
        system.out.println( "=======方法执行后======" );
    }

    // 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点;
    // 可以获取切入点的相关信息。
    @Around( "execution(*com.kuang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        
        system.out.println("环绕前");
        
        object proceed = jp.proceed();	//执行方法
        
        system.out.println("环绕后");
    }
}

10.3 Spring AOP 五大通知

  • Before 前置通知

  • AfterReturning 后置通知

  • Around 环绕通知

  • AfterThrowing 异常通知

  • After 最终通知

五种通知的执行顺序

  1. 在目标方法没有抛出异常的情况下

    前置通知 → 环绕通知的调用目标方法之前的代码 → 目标方法 → 环绕通知的调用目标方法之后的代码 →

    后置通知 → 最终通知

  2. 在目标方法抛出异常的情况下
    前置通知 → 环绕通知的调用目标方法之前的代码 → 目标方法 → 抛出异常 异常通知 → 最终通知

11、整合Mybatis

详细内容可以查看文档

11.1 基础方式

  1. 导入相关Jar包

    • Junit
    • Mybatis
    • MySQL数据库
    • Spring 相关
    • AOP 织入
    • mybatis-spring 【new】
  2. 编写 Spring 、Mybatis 配置文件

    <!-- spring-dao.xml -->
    <!-- 数据库的配置,一般不改,直接import进 Spring 的总配置文件 -->
    <?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">
    
        <!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 
    		 我们这里使用Spring提供的JDBC:org.springframework.jdbc.datasource -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value "jdbc:mysql://localhost:3306/mybatis?useSSL=true"/>
            <property name="username" value="root" />
            <property name="password" value="123456"/>
        </bean>
    
        <!-- sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="datasource" ref="datasource"/>
            <!-- 绑定Mybatis配置文件 -->
            <property name="configLocation" value="classpath:mybatis-config.xml" />
            <property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
        </bean>
    
        <!-- sqlSessionTemplate:就是我们使用的sqlSession -->
        <bean id="sqlSession" class="org.mybatis.spring.sqlsessionTemplate">
            <!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法 -->
            <constructor-arg index="0" ref="sqlSessionFactory" />
        </bean>
    </beans>
    
    <!-- appplicationContext.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">
        <import resource="spring-dao.xml"/>
        
        <!-- Mapper的实现类 -->
        <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
            <property name="sqisession" ref="sqlsession" />
        </bean>
    
    </beans>
    
  3. 写 Mapper.xml(sql语句)

    ......

  4. 写 Mapper 的实现类 MapperImpl

    import org.mybatis.spring.sqlSessionTemplate;
    import java.util.List;
    public class UserMapperImpl implements UserMapper {
        
        private sqlsessionTemplate sqlsession;
        
        public void setSqlSession(sqlSessionTemplate sqlSession) { 
            this.sqlSession = sqlSession;
        }
        
        public List<User> selectUser() {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            return mapper.selectuser();
        }
    }
    

11.2 SqlSessionDaoSupport

  • 实现类去掉属性 sqlSession 和 set 方法
  • 直接通过getSqlSession()获取sqlSession,无需注入依赖
import org.mybatis.spring.sqlSessionTemplate;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

    public List<User> selectUser() {
        return getSqlSession().getMapper(UserMapper.class).selectuser();
    }
}

同时,在 spring-dao.xml 中去掉:

<!-- sqlSessionTemplate:就是我们使用的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.sqlsessionTemplate">
    <!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法 -->
    <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

并修改:

<!-- Mapper的实现类 -->
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
    <property name="sqisession" ref="sqlsession" />
</bean>

<!-- 修改为 -->
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
    <!-- 父类 SqlSessionDaoSupport 需要 sqlSessionFactory工厂实例 -->
    <property name="sqlSessionFactory" ref="sqlsessionFactory" />
</bean>

12、事务

12.1 什么叫事务?

  • 把一组业务当成一个业务来做;要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎!·确保完整性和一致性;
  • 事务ACID原则:
    • 原子性:一个事务要么全部执行,要么不执行。
    • 一致性:数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性。
    • 隔离性:多个业务可能操作同一个资源,防止数据损坏。
    • 持久性:事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中。

12.2 Spring 事务管理

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

为什么需要事务?

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

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

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

12.3 Spring 声明式事务

<!-- spring-dao.xml -->

<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- 给哪些方法配置事务(需要结合事务的方法丢进去) -->
    <!-- 配置事务的传播特性: propagation -->
    <tx:attributes>
        <tx:method name="add" propagation="REQUIRED"/>
        <tx:method name="delete" propagation="REQUIRED"/>
        <tx:method name="update" propagation="REQUIRED" />
        <tx:method name="query" read-only="true" />
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<!-- 配置事务切入 -->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>
这篇关于Spring学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!