Spring5 学习

Spring5 学习

简介

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

导包

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


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

优点

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

Spring组成及扩展

组成

image-20211005213902948

ORM 对象关系映射

image-20211005214147527

现代化的开发:基于spring的开发

springboot:

  • 一个快速开发的脚手架:
  • 基于SpringBoot 可以快速的开发单个微服务
  • 约定大于配置

SpringCloud

  • SpringCloud是基于SpringBoot 实现的

弊端: 违背了 当初的理念,需要配置大量的东西

IOC理论推导

创建UserDao接口,以减少代码;系统的耦合性降低

IOC本质

image-20211007123342008

控制反转(inversion of control), 是一种设计思想,DI(dependency injection依赖注入)是IOC的一种方法。未使用IOC的程序中,我们使用面向对象编程,对象的创建和对象之间的依赖关系完全硬编码在程序中,对象的创建是由程序自己控制的。控制反转就是将对象的创建转移给了第三方.IOC就我认为是:获得依赖对象的方式反转了

DI只是实现IOC的一种方法

image-20211007123623138

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

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

Hello Spring

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

对象是由Spring创建的,对象的属性是由Spring 设置的 这个过程就叫做控制反转

image-20211007132418719

具体使用

image-20211007134137897

ref 引用Spring容器中已经创建好的对象

value是所创建的对象的具体的值

对象由Spring来创建 管理 和分配

IOC创建对象方式

使用构造器创建对象

  1. 使用无参构造器 创建对象

  2. 使用有参构造创建对象

    • 使用下标赋值法创建对象

        <bean id="hello" class="com.hai.spring.pojo.Hello">
              <constructor-arg index="0" value="海洪健" />
          </bean>
      
    • 使用类型进行赋值

      <bean id="hello" class="com.hai.spring.pojo.Hello">
              <constructor-arg type="java.lang.String" value="海洪健"/>
          </bean>
      
      但是这种方法不建议使用 当有多个参数类型相同时,容易出现错误
      
    • 直接通过参数名设置

      <bean id="hello" class="com.hai.spring.pojo.Hello">
              <constructor-arg name="str" value="海洪健" />
          </bean>
      

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

Spring配置说明

别名

<alias name="hello" alias="hello2"/>
改成什么都可以使用

Bean的配置 通过配置来实现IOC

   <bean id="hello" class="com.hai.spring.pojo.Hello" name="hello2 hello3,hello4">
        <property name="str" value="海洪健"/>
   </bean>

    <!--    id bean的唯一标识 相当于创建对象时 的对象名
            class  bean 对象所对应的全限定名 包名+类型
            name 也是别名 而且name还可以取多个别名
     -->

import配置

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

<import resource=""/>

DI 依赖注入环境

三种方式 构造器注入

构造器注入

constructor-arg 这种方式 就属于构造器注入

Set方式注入(重点) 要写 set方法

依赖注入:set注入

依赖:bean 对象的创建依赖于容器

注入:bean对象中的所有属性,由容器来注入

第一种:普通值注入 value

<bean id="student" class="com.hai.spring.pojo.Student">
        <property name="name" value="海洪健"/>
</bean>

第二种: 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>RAP</value>
                <value>打篮球</value>
            </list>
        </property>

​ 第五种:map注入

 <property name="card">
            <map>
                <entry key="身份证号" value="371482200001011100"/>
                <entry key="年龄" value="21"/>
            </map>
        </property>

第六种:set注入

  <property name="games">
            <set>
                <value>LOL</value>
                <value>COD</value>
                <value>王者</value>
            </set>
        </property>

第七种:空值注入

 <property name="info">
            <props>
                <prop key="学号">202031008010</prop>
                <prop key="成绩">98</prop>
            </props>
        </property>

扩展方式注入

c命名和p命名空间注入方式

p命名空间
<!--  p 命名空间 可以直接注入属性的值 P:property 相当于property -->
    <bean id="user" class="com.hai.spring.pojo.User" p:name="海洪健" p:age="19">
<!--        <property name="name" value="海洪健"/>-->
<!--        <property name="age" value="19"/>-->
    </bean>
c命名空间
<!--    c命名空间注入 相当于构造器注入-->
    <bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20"/>

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

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

Bean的作用域

image-20211007192717814

默认的是单例模式 也可以显示的定义

单例模式 默认是单例模式

<bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20" scope="singleton"/>

原型模式

<bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20" scope="prototype"/> 

原型模式会产生两个不同的对象,并且是每次get,都会产生一个新的对象

这里的get获取bean

其余的都是在web开发中会用到

自动装配bean

  • 自动装配是满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,被自动给bean装配属性

在Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在Java中显示的进行配置
  3. 隐式的自动装配bean

ByName自动装配 通过名字来是实现自动装配

xml配置

 	<bean id="cat" class="com.hai.spring.pojo.Cat"></bean>
    <bean id="dog" class="com.hai.spring.pojo.Dog"></bean>
    <bean id="people" class="com.hai.spring.pojo.People" autowire="byName">
        <property name="name" value="海洪健"/>
    </bean>

java测试代码

一个人 两个宠物 两个宠物只有方法的实现 没有成员变量

 @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people = context.getBean("people",People.class);
        System.out.println(people.getName());
        people.getCat().shut();
        people.getDog().shut();

    }

byType 通过类型查找

!--    ByTYpe 自动装配会自动在容器的上下文中查找 与自己的类型相同的beanId  但是它有弊端  必须得保证类型全局唯一-->
    <bean id="people" class="com.hai.spring.pojo.People" autowire="byType">
        <property name="name" value="海洪健"/>
    </bean>

小结:

  1. byname的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一样
  2. bytype的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一样

使用注解进行自动装配

jdk1.5支持的注解 Spring2.5 支持的注解

使用注解须知:

  1. 导入约束: context约束
  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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.0.xsd
       ">
    <!-- 扫描包含注解定义的类包-->
    <context:annotation-config/>
</beans>

@Autowired自动装配注解

@Autowired
可以直接在属性上使用  也可以在set方法上使用
使用@Autowired 我们可以不用写set方法了 前提是你这个自动装配的属性在IOC(Spring) 容器中是存在的,且命名符合ByName

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

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

使用nullable标记了这个注解 说明这个字段可以为空  并且还不会报错

@Autowired自动装配注解参数设置

 注解装配在属性上

@Autowired(required = false)
    private Dog dog;
required = false 将required设置为空 说明这个对象可以为null,否则不允许为空

@Qualifier 在id名和class名都不相同时。可以结合使用Qualifier 来实现自动装配 Qualifier 中有一个参数为value 专门用来解决这个问题

@Resource Java注解

@Resource
private Dog dog;

这个注解先通过 名字(name)进行查找 名字查找不到 通过类型进行查找 如果名字和类型都查找不到,才会报错

 @Resource(name = "dog")

也可以通过指定名字进行注解

小结

@Resource和@Autowired 之间的区别

  • 都是用来自动装配的,都可以放在字段上
  • @Autowired 是通过byType的方式实现的,而且必须要求这个对象存在 通过类型来实现
  • @Resource 默认通过byName 的方式来实现,如果找不到名字,则通过byTYpe来实现,如果两个都找不到,则进行报错
    通过名字来实现
  • 执行顺序不同,@Autowired 通过byType来实现

Spring注解开发

在Spring4之后,如果想使用注解进行开发,必须导入aop的包

Component

组件 使用方法为放到类上 说明这个类被Spring管理了 就是bean

属性注入

@Value("海洪健")
public String name;
通过value可以设置值 简单的可以使用 复杂的推荐使用配置文件

衍生的注解

在web开发中每一层都有自己的注解

dao @Repository
controller  @Controller
service @service
bean  @Component
这四个注解的功能都是一样的  都是将某个类注册到Spring容器中

xml与注解之间的区别

  • xml更加的万能,适用与任何的场合!维护也相对简单。
  • 注解 不是自己的类使用不了,维护相对的复杂!

xml与注解的最佳实现:

  • xml只用来管理
  • 注解只负责完成属性的注入;
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持。

使用JavaConfig实现配置

Userpackage com.hai.spring.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 自动注解
@Component
public class User {
    private String name;

    public User() {
    }


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

    public String getName() {
        return name;
    }
    @Value("海洪健")
    public void setName(String name) {
        this.name = name;
    }
}
config 类
    
// @Configuration  @Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
    // 要求
    //@Configuration不可以是final类型;
	//@Configuration不可以是匿名类;
	//嵌套的configuration必须是静态类。
package com.hai.spring.config;

import com.hai.spring.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 获取新的用户 这个注解用于定义配置类 可替换 xml配置文件
@Configuration
public class MyConfig {
    @Bean
    public User getUser() {
        return new User();
    }
}
测试类
package com.hai.test;

import com.hai.spring.config.MyConfig;
import com.hai.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestOne {
    // context 获取Spring的上下文对象
    // 获取ApplicationContext 拿到Spring容器
    // 我们的对象都在Spring进行管理了,如果要使用,直接取出来就可以了
    @Test
    public void test() {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user  = (User) context.getBean("getUser");
        System.out.println(user.getName());
    }
}

代理模式

为什么要学习代理模式? 因为代理模式就是Spring-Aop 的底层

SpringAop 和 SpringMvc重点 公司都会问

静态代理模式

代理就是帮我做事情 和中介查不多

角色分析:

抽象角色: 一般会用接口或者是抽象类来解决

真实角色: 被代理的角色

代理角色: 代理真实角色,代理真实角色后,我们一般会做一些附属操作

客户:访问代理角色的人

代理模式的好处:

  • 可以使真实角色的操作更加的纯粹。不用去关心一些公共的事务
  • 公共事务交给代理角色。实现了业务的分工
  • 公共业务发生扩展时,方便集中管理

缺点:

  • 一个真实的角色就会产生一个代理角色,这样会导致代码量翻倍。开发效率会变低。解决这个问题的方法就是动态代理

代理的步骤:

  1. 租房子接口

    public class Rent {
        public void rent();
    }
    
  2. 房东租房子 实现接口

    public class host implements Rent{
        public void rent() {
            System.out.println("我要租房子!");
        }
    }
    
  3. 代理待租房子 有自己的一些方法

    public class dali {
        private Host host;
        public dali(){}
        public dali(Host host) {
            this.host = host;
        }
        public void rent() {
            host.rent();
        }
    }
    
  4. 客户端访问租房子

    public class customer {
        @Test
        public void test() {
            Host host = new Host();
            Dali dali = new Dali(host);
            dali.rent();
        }
    }
    

    静态代理的解决方法就是动态代理

    输出一个日志 我们可以通过增加 代理的方式来实现 尽量的去增加东西 而不是删除东西

动态代理详解

动态代理运用的是反射这个技术

  • 动态代理和静态代理的角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
  • 基于接口— JDK动态代理 【我们在这里使用】
  • 基于类: cglib
  • java 字节码实现 : Javasist

需要了解两个类: Proxy : 代理 ,InvocationHandler:调用处理

InvocationHandler

image-20211010150655571

image-20211010150956658

动态代理的好处

  • 可以使真实角色的操作更加的纯粹。不用去关心一些公共的事务
  • 公共事务交给代理角色。实现了业务的分工
  • 公共业务发生扩展时,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。

AOP

什么是AOP

image-20211010160116688

image-20211010160155672

image-20211010161419425

image-20211010161431157

导包

使用SpringAop的时候,我们必须得导包

 <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.7</version>
 </dependency>

AOP的配置文件头

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

AOP的实现流程

ApplicationContext 文件

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--    注册bean-->
    <bean id="userService" class="com.hai.spring.service.UserServiceImpl"/>
    <bean id="beforeLog" class="com.hai.spring.log.BeforeLog"/>
    <bean id="afterLog" class="com.hai.spring.log.AfterLog"/>

    <!--方式一  使用原生的Spring API  接口 -->
    <!--配置AOP 需要导入aop 的约束 -->
    <aop:config>
        <!-- 切入点: expression 表达式 execution 要执行的位置! * * * * *-->
        <aop:pointcut id="pointcut" expression="execution(* com.hai.spring.service.UserServiceImpl.*(..))"/>

<!--        执行环绕增加!-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

接口

package com.hai.spring.service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}


public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("增加了一个用户!");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户!");
    }

    @Override
    public void update() {
        System.out.println("更改了一个用户!");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户!");
    }
}
执行前
package com.hai.spring.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {

    // method: 要执行的目标对象的方法
    // args: 参数
    // target: 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
    }
}
执行后
package com.hai.spring.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    // returnValue 执行后具有反回值 这个值就是返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法!");
    }
}

AOP 实现方法二

方法二:使用自定义类来实现 AOP

自定义切入点 切入点中放通知

主要是切面定义

    <bean id="diy" class="com.hai.spring.diy.DiyPointCut"/>
    <aop:config>
<!--        第一个星号代表反回值类型  第二个星号代表包-->
        <!--           自定义切面  ref 指的是要引用的类 -->
        <aop:aspect ref="diy">
            <!--切入点-->
             // execution中放的是程序要执行的位置
            <aop:pointcut id="pointcut" expression="execution(* com.hai.spring.service.UserServiceImpl.*(..))"/>
<!--    通知 要执行的方法        -->
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
package com.hai.spring.diy;

public class DiyPointCut {
    public void before() {
        System.out.println("========方法执行前==========");
    }
    public void after() {
        System.out.println("========方法执行后==========");
    }
}
test 测试类
public class TestOne {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        // 因为动态代理代理的是一个接口 不是一个类 所以我们要使用接口
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }
}

注解实现AOP

<!--    方式三-->
    <bean id="annocationPointcut" class="com.hai.spring.diy.AnnocationPointcut"/>
<!--     开启注解支持-->
<!--     注解支持默认使用jdk-->
    <aop:aspectj-autoproxy/>
@Aspect
public class AnnocationPointcut {

    @Before("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("开始前!");
    }
    @After("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("开始后!");
    }
    @Around("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前!");
        Object object = jp.proceed();
        System.out.println("环绕后!");
    }
}

回顾Mybatis

mybatis 核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 起别名 -->
    <typeAliases>
        <package name="com.hai.spring.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>
    <mappers>
        <!--        <mapper resource="com/hai/mybatis/mapper/UserMapper.xml"/>-->
        <!--        userMapper 和 xml文件的名字要相同 -->
        <package name="com.hai.spring.mapper"/>
    </mappers>
</configuration>
mappper配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hai.spring.mapper.UserMapper">
    <resultMap id="UserMap" type="com.hai.spring.pojo.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="pwd"/>
    </resultMap>
    <select id="getUser" resultMap="UserMap">
        select * from mybatis.users
    </select>
</mapper>
测试
package com.hai.test;

import com.hai.spring.mapper.UserMapper;
import com.hai.spring.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.List;

public class TestOne {
    private SqlSession sqlSession;
    private UserMapper userMapper;

    @Before
    public void before() throws IOException {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        sqlSession = factory.openSession();
    }
    @Test
    public void getUser() {
        userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list =  userMapper.getUser();
        for (User user : list) {
            System.out.println("user = " + user );
        }
    }
    @After
    public void after() {
        sqlSession.close();
    }

}

Mybatis 与 Spring 整合

方法一

template 模板

整合数据源 SqlSessionFactory SqlSessionTemplat

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    DataSource 数据源  使用Spring的数据源 替换 mybatis的配置
       我们这里使用Spring 提供的数据源
 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=UTC"/>
        <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 配置文件 mybatis 资源的位置-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- mapper 的位置 -->
        <property name="mapperLocations" value="classpath:com/hai/spring/mapper/*.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只能使用构造器注入SqlSessionFactory 因为没有 set方法   创建sqlSessionFactory 对象  -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.hai.spring.mapper.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>
</beans>

创建实现类 实现mybatis 所作的工作

package com.hai.spring.mapper;

import com.hai.spring.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{

    ///  我们的所有操作 都将使用 SqlSessiontemplate 来做
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> getUser() {
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.getUser();
    }
}

测试实现类

package com.hai.test;

import com.hai.spring.mapper.UserMapper;
import com.hai.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class TestTwo {
    @Test
    public void test() {
        // 通过application上下文拿到  spring 容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationConText.xml");
        UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
        List<User> list = userMapper.getUser();
        for (User user : list) {
            System.out.println("user =" + user );
        }
    }
}

方法二:

package com.hai.spring.mapper;

import com.hai.spring.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperTwo extends SqlSessionDaoSupport implements UserMapper {

    @Override
    public List<User> getUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        return userMapper.getUser();
    }
}
<bean id="userMapper2" class="com.hai.spring.mapper.UserMapperTwo">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

方式二只需要配置 SqlSessionFactory 不需要配置别的

事务回顾

把一组事务当成一个事务来做,要么都成功 要么都失败

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

确保完整性和一致性

事务的ACID 原则

1. 原子性
   2. 一致性
   3. 隔离性: 多个事务之间互不干扰 为了保护数据
   4. 持久性  事务一旦提交 无论系统发生什么事情  结果都不会被更改 被持久化的保存了

Spring声明式事务

七种配置事务的传播特性的方法

image-20211014160241684

image-20211014160925629

事务需要我们手动的在xml文件中配置
我们需要手动开启事务
配置切入点 在切入点中插入事务
<!--    配置声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>

<!--    结合AOP实现事务的织入-->
<!--    配置事务通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--    给那些方法配置事务       -->
<!--     配置事务的传播特性    new  propagation -->
            <tx:attributes>
                <tx:method name="add" propagation="REQUIRED"/>
                <tx:method name="delete"/>
                <tx:method name="update"/>
                <tx:method name="query"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>

<!--     配置事务切入 就是配置 AOP 的操作  配置切入点 在切入点上配置上操作-->
        <aop:config>
            <aop:pointcut id="txPointCut" expression="execution(* com.hai.spring.mapper.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
        </aop:config>

总结

重点是理解思想

笔记持续完善

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值