• Spring知识点总结-DX的笔记


    什么是Spring?

    优点

    • 轻量级的开源框架
      • 轻量级:非侵入性。基于spring框架开发的类可以不依赖于spring的API
      • 作用:管理java对象,控制对象的生命周期(IOC)
      • MVC三层架构
        • 控制层 controller
        • 业务层 service
        • 持久层 dao
    • 控制反转IOC、面向切面AOP
    • 支持事务、整合现有的框架技术
    • 一句话概述:Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)

    Spring的组成(七个模块)

    请添加图片描述
    在这里插入图片描述

    • Spring框架是一个分层架构,由七个模块组成

    • Spring模块构建在核心容器之上

    • 每个模块(或组件)可以单独存在,也可以和其他模块联合使用

    • 1.核心容器

      • 核心容器定义了创建、配置和管理bean的方式,提供 Spring 框架的基本功能
      • 核心容器的主要组件是 BeanFactory ,BeanFactory 使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开
      • 核心容器包括
        • spring-core:模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能
        • spring-beans:提供 BeanFactory
        • spring-context:Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能
        • spring-context-support:提供了强大的表达式语言,用于在运行时查询和操作对象图
        • spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)
        • 等模块组成
    • 2.Spring上下文

      • Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息
      • 包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能
    • 3.Spring AOP

      • 通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中
      • 所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象
      • Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务
      • 通过使用 Spring AOP,不用依赖组件,就可以 将声明性事务管理集成到应用程序中
    • 4.Spring DAO

      • JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息
      • 异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)
      • Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构
    • 5.Spring ORM

      • Spring框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具
      • 其中包括 JDO、Hibernate 和 iBatis SQL Map,所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构
    • 6.Spring Web模块

      • Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文
      • 所以,Spring 框架支持与 Jakarta Struts 的集成
      • Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作
    • 7.Spring MVC 框架

      • MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现
      • 通过策略接口,MVC 框架变成为高度可配置的
      • MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI

    IOC(控制反转)

    • 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法
    • 控制反转:将开发者手中的对Java对象的控制权交给Spring框架的过程。通过配置Bean实现
    • IOC容器:存放Spring创建出来对象的一个容器
    • IoC是Spring框架的核心内容,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC
    • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式
    • 在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)

    bean标签

    属性介绍

    1. id
      • 是 bean的唯一标识
      • 整个IOC 容器 id 值不允许重复,使用名称作为key
    2. name
      • 一个bean的名称,可以存在多个,多个之间使用逗号分隔
      • 如果没有定义name属性,默认id都会当做name。
    3. class
      • bean的具体的类型,包名和类名组成。
    4. scope
      • bean的作用域
    5. prototype
      • 非单例,每次获取都会创建一个新的bean对象。
    6. singleton
      • 单例,多次获取永远同一个bean, 默认值。
    7. request
      • 一次请求,基于web项目的bean的作用域。
    8. session
      • 一次会话,基于web项目的bean的作用域。
    9. lazy-init
      • 延迟初始化
      • 默认加载配置文件时,bean对象就会被初始化,
      • azy-init则是获取时才会初始化
      • 只针对单例模式有效,非单例每次获取都会创建,没有延迟初始化的意义
    10. depends-on
      • 初始化时依赖的对象
      • 当前对象初始化前需先初始化depends-on指定的对象
    11. init-method
      • 对象初始化后,调用的方法
    12. destroy-method
      • 对象销毁时,调用的方法
    13. autowire
      • 属性自动装配
    14. byName
      • 根据属性名称装配
    15. byType
      • 根据类型装配
    16. autowire-candidate
      • 是否允许作为自动装配的候选项
      • true 作为自动装配的候选项
      • false 不作为自动装配的候选项
    17. primary
      • 优先使用该bean
      • 因为Spring需要支持使用类型查找对象,在一个大类型下,可能存在多个小类型
      • 如果根据大类型装配属性时,不知道使用哪个具体的对象,则可以根据primary

    使用流程

    • maven依赖配置

      <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-contextartifactId>
          <version>5.3.18version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • applicationContext.xml

      
      <bean id="hello1" class="com.dx.bean.HelloSpring"/>
      
      <bean id="hello" class="com.dx.bean.HelloSpring" primary="true"/>
      
      • 1
      • 2
      • 3
      • 4
    • test.java

      /**
       * 获取对象,并调用其方法
       * */
      @Test
      public void iocTest(){
          //1.初始化ioc容器
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          //2.从容器中取出对象
          //方式1:通过name获取Bean对象,如果有多个此类型的bean对象时,获取标识的主bean,如果没有标识则抛异常
          HelloSpring hello = (HelloSpring) ac.getBean("hello");
          //方式2:通过bean的类型获取Bean对象
          HelloSpring hello1 = ac.getBean(HelloSpring.class);
          //方式3:通过name和类型获取Bean对象
          HelloSpring hello2 = ac.getBean("hello",HelloSpring.class);
          hello.show();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    bean的作用域

    • singleton: 单例,默认

      • 一个bean标签在整个IOC容器中仅会创建一个对象
      • 在IOC容器创建完成之后,立即创建,无论是否使用到此bean
    • prototype: 原型(多例)

      • 一个bean标签在整个IOC容器中会创建多个对象
      • 在IOC容器初始化时不会创建任何对象,只有在使用bean时,才会去创建对象,每次创建的都是新对象
    • 用法

      <bean id="book" class="com.bjpowernode.bean.Book" scope="singleton"/>
      <bean id="book" class="com.bjpowernode.bean.Book" scope="prototype"/>
      
      • 1
      • 2

    bean的生命周期

    • 通过构造方法创建Bean对象

    • 为Bean对象中的成员变量赋值

    • 调用Bean对象中初始化方法(init-method)

    • Bean对象的使用

    • 当容器关闭之前,调用Bean对象的销毁方法(destroy-method)

    • applicationContext.xml

      
      <bean id="dog" class="com.bjpowernode.bean.Dog" init-method="init" destroy-method="destroy">
      	<property name="name" value="哈士奇"/>
      bean>
      
      • 1
      • 2
      • 3
      • 4
    • Dog.java

      public class Dog {
          private String name;
          public Dog(){
              System.out.println("Dog对象被创建...");
          }
          public void init(){
              System.out.println("Dog对象的初始化方法...");
          }
          public String getName() {
              return name;
          }
          public void setName(String name) {
              System.out.println("name属性被赋值...");
              this.name = name;
          }
          public void destroy(){
              System.out.println("Dog对象的销毁方法...");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • test.java

      @Test
      public void lifeCycle() {
          System.out.println("=============IOC容器初始化阶段===============");
          ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
      
          System.out.println("=============对象使用阶段===============");
          Dog dog = ac.getBean("dog", Dog.class);
          System.out.println(dog);
          System.out.println(dog.getName());
          
          System.out.println("=============IOC容器关闭阶段===============");
          ac.close();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

    depends-on属性

    • 先创建指定的bean,再创建自己

    • 
      <bean id="emp" class="com.dx.bean.Emp" depends-on="dept"/>
      <bean id="dept" class="com.dx.bean.Dept"/>
      
      • 1
      • 2
      • 3

    创建bean对象的四种方式

    1. 构造方法

      • 通过反射机制调用类中无参或有参构造方法来是实现Bean的创建

      • 
        <bean id="cat" class="com.dx.bean2.Cat"/>
        
        • 1
        • 2
      • public class Cat {
            public String name;
            @Override
            public String toString() {
                return name + "猫咪对象";
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
      • 测试类(下同)

        @Test
        public void factory() {
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            Cat cat = ac.getBean("cat", Cat.class);
            System.out.println(cat);
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
    2. 静态工厂,实例工厂

      • 通过一个工厂类来间接实现对象创建,将Bean对象放置在IOC容器

      • 
        <bean id="cat1" class="com.dx.factory.CatStaticFactory" factory-method="getInstance"/>
        
        • 1
        • 2
        /* Cat对象的静态工厂 */
        public class CatStaticFactory {
            public static Cat getInstance(){
                Cat cat = new Cat();
                cat.name = "加菲猫";
                return cat;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
      • 
        <bean id="factory" class="com.dx.factory.CatInstanceFactory"/>
        <bean id="cat2" factory-method="getInstance" factory-bean="factory"/>
        
        • 1
        • 2
        • 3
        /* Cat对象的实例工厂 */
        public class CatInstanceFactory {
        
            public Cat getInstance(){
                Cat cat = new Cat();
                cat.name = "黑猫警长";
                return cat;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
    3. FactoryBean接口

      • 
        <bean id="cat3" class="com.dx.factory.CatFactoryBean"/>
        
        • 1
        • 2
        /* 实现FactoryBean接口 */
        public class CatFactoryBean implements FactoryBean<Cat> {
            /*获取对象*/
            @Override
            public Cat getObject() throws Exception {
                Cat cat = new Cat();
                cat.name = "小花猫";
                return cat;
            }
            /*获取对象的Class类型*/
            @Override
            public Class<?> getObjectType() {
                return Cat.class;
            }
            /*配置当前对象是否为单例模式*/
            @Override
            public boolean isSingleton() {
                return true;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
    4. 注解

      略,在后面

    依赖注入(DI)

    • Dependency Injection

    • 依赖:在A类中使用B类:A类对B类产生依赖关系。

      • public class Classes{}
        
        public class Student{
           	String sname;
            Integer age;
            Double score;
            Classes classes;
            public static void main(String[] args){
                Student s1 = new Student();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
      • 可以说Student类对String, Integer, Double, Classes类产生了依赖关系

    • 注入:为依赖类型的变量赋值

    • 所谓控制反转就是:获得依赖对象的方式反转了

    注入属性的类型

    1. 简单类型数据: 使用字符串可以表示的数据 int, double, boolean, Date
    2. 自定义对象(POJO)
    3. 集合,数组

    属性注入的三种方式

    1. 构造方法

      public class Car {
          private Integer id;
          private String name;
          private String type;
          private Double price;
          
          public Car(Integer id, String name, String type, Double price) {
              this.id = id;
              this.name = name;
              this.type = type;
              this.price = price;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      
      <bean id="car" class="com.dx.bean2.Car">
          
          <constructor-arg value="001"/>
          <constructor-arg value="奥迪"/>
          <constructor-arg value="轿车"/>
          <constructor-arg value="49.0"/>
          
          
          <constructor-arg value="奥迪" index="1"/>
          <constructor-arg value="001" index="0"/>
          <constructor-arg value="49.0" index="3"/>
          <constructor-arg value="轿车" index="2"/>
          
          <constructor-arg value="奥迪" name="name"/>
          <constructor-arg value="001" name="id"/>
          <constructor-arg value="49.0" name="price"/>
          <constructor-arg value="轿车" name="type"/>
      bean>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
    2. set方法

      • public class Student {
            private String name;
            private Integer age;
            private Double score;
            private Boolean gender;
            private Date birthday;
            private Address address;
            private String[] courseNames;
            private List<String> list;
            private Set<Integer> set;
            private Map<String, Double> map;
            private Properties properties;
            //set和get方法这里省略了
            //......
        }
        
        public class Address {
            private String city;
            private String area;
            private String street;
            //set...... get......
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        
        <bean id="student" class="com.dx.bean2.Student">
            
            <property name="name" value="小明"/>
            <property name="age" value="22"/>
            <property name="score" value="86.5"/>
            <property name="gender" value="true"/>
            
            <property name="birthday" value="1998/05/19"/>
        
            
            
            
            
            
            
            
            
            <property name="address">
                <bean class="com.dx.bean2.Address">
                    <property name="city" value="北京市"/>
                    <property name="area" value="海淀区"/>
                    <property name="street" value="人民路"/>
                bean>
            property>
        
            
            <property name="courseNames">
                <array>
                    <value>语文value>
                    <value>数学value>
                    <value>外语value>
                array>
            property>
        
            
            <property name="list">
                <list>
                    <value>aaavalue>
                    <value>bbbvalue>
                    <value>cccvalue>
                    <value>dddvalue>
                list>
            property>
        
            
            <property name="set">
                <set>
                    <value>10value>
                    <value>20value>
                    <value>30value>
                    <value>40value>
                set>
            property>
        
            
            <property name="map">
                <map>
                    <entry key="one" value="1.2"/>
                    <entry key="two" value="2.6"/>
                    <entry key="three" value="3.14"/>
                map>
            property>
        
            
            <property name="properties">
                <props>
                    <prop key="jdbc.driver">com.mysql.jdbc.Driverprop>
                    <prop key="jdbc.url">jdbc:mysql://localhost:3306/testprop>
                    <prop key="jdbc.username">rootprop>
                    <prop key="jdbc.password">123prop>
                props>
            property>
        bean>
        
        <bean id="address" class="com.dx.bean2.Address">
            <property name="city" value="郑州市"/>
            <property name="area" value="金水区"/>
            <property name="street" value="民航路"/>
        bean>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58
        • 59
        • 60
        • 61
        • 62
        • 63
        • 64
        • 65
        • 66
        • 67
        • 68
        • 69
        • 70
        • 71
        • 72
        • 73
        • 74
        • 75
        • 76
        • 77
        • 78
        • 79
        • 80
    3. 注解

      略,在后面

    p/c命名空间注入(扩展)

    • P命名空间注入(注入属性: properties)

      导入约束 : xmlns:p="http://www.springframework.org/schema/p"
      
      <bean id="user" class="com.dx.pojo.User" p:name="dx" p:age="18"/>
      
      • 1
      • 2
      • 3
    • C命名空间注入(注入构造方法的参数: Constructor)

      导入约束 : xmlns:c="http://www.springframework.org/schema/c"
      
      <bean id="user" class="com.dx.pojo.User" c:name="dx" c:age="18"/>
      
      • 1
      • 2
      • 3

    自动装配

    • 在进行自定类型的数据依赖注入时,IOC容器会自动查找匹配对象,实施依赖注入

    • 条件:仅限于自定义类型的数据(POJO)

    • 实现:autowire属性

    • 类型:

      • no: 不自动装配

      • byName: 根据属性名称匹配,如果没有找到Bean,不进行自动装配,不会报错。

      • byType: 根据属性类型匹配,如果没有找到此类型Bean,不进行自动装配,不会报错。

        但是如果找到多个没有标识Primary的Bean,就是报错。

      • default: 默认值,会根据父标签beans标签中default-autowire属性来取值。

    • 缺点: 不灵活,不能实现即能根据名称匹配又能根据类型匹配

    • 实现

      public class Order {
          private String orderNum;
          private Double price;
          private Customer customer;
          //get set....
      }
      public class Customer {
          private String username;
          private String password;
          //get set....
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      <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"
              default-autowire="byName">
      
              
              <bean id="order" class="com.dx.bean2.Order" autowire="byType">
                  <property name="orderNum" value="XA20220712001"/>
                  <property name="price" value="3998"/>
              bean>
      
              <bean id="cust" class="com.dx.bean2.Customer" primary="true">
                  <property name="username" value="tom"/>
                  <property name="password" value="123"/>
              bean>
              <bean id="customer" class="com.dx.bean2.Customer">
                  <property name="username" value="jerry"/>
                  <property name="password" value="321"/>
              bean>
      beans>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      @Test
      public void autowire() {
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          Order order = ac.getBean("order", Order.class);
          System.out.println(order);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    使用注解

    1. 组件扫描
    • 先配置命名空间和标签规范。配置在当前项目中哪些包中注解是生效的。

    • xmlns:context="http://www.springframework.org/schema/context"
      
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      
      • 1
      • 2
      • 3
      • 4
    1. 配置Bean

      • @Component
      • @Controller
      • @Service
      • @Repository
      • 此以上四种注解在IOC模块中功能上没有区别,都是配置Bean。
      • 不建议大家混用。在Spring项目中,控制层使用@Controller,业务层@Service,持久层@Repository,@Component配置除三层架构之外的类。
      • @Scope:配置作用域,例如:@Scope(“prototype”)配置为多例模式
    2. 依赖注入

      • @Value 简单类型
      • @Autowired 自定义类型
        • Spring中的注解。先根据类型匹配,再根据名称匹配
        • @Autowired(required=false):默认为true,如果没有找到bean会报错,设为false后,不会报错
        • @Qualifier(“beanName”):当有多个bean时,根据名字指定bean
        • @Primary:当有多个bean切无法自动匹配时,可使用这个注解设置主bean
      • @Resource 自定义类型
        • jdk中的注解,spring作了扩展支持。先根据名称匹配,再根据类型匹配
    3. 使用方法

      • // @Controller
        // @Service
        // @Repository
        @Component("dd")
        // @Primary
        public class Department {
            @Value("10")
            private Integer id;
            @Value("研发部")
            private String dname;
            //get... set...
        }
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Component("abc")
        public class Employee {
            @Value("123")
            private Integer id;
            @Value("张三")
            private String ename;
            @Autowired
            @Qualifier("dd")    //通过注解指定bean
        //    @Resource
            private Department department;
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
      •   
          
          
          <context:component-scan base-package="com.dx"/>
        
          
          <bean id="department" class="com.dx.bean2.Department">
              <property name="id" value="666"/>
              <property name="dname" value="李四"/>
          bean>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      •    @Test
           public void annotation() {
               ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
               //依赖注入简单类型
               Department department = ac.getBean("dd", Department.class);
               System.out.println(department);
               //依赖注入自定义类型
               Employee employee = ac.getBean("abc", Employee.class);
               System.out.println(employee);
           }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

    代理模式(了解)

    静态代理

    • 实现方法

      public interface UserDao {
          void insert();
          void update();
          void delete(int id);
          List<String> select();
      }
      
      public class UserDaoImpl implements UserDao {
          @Override
          public void insert() {
              System.out.println("UserDaoImpl---->insert...........");
          }
          @Override
          public void update() {
              System.out.println("UserDaoImpl---->update...........");
          }
          @Override
          public void delete(int id) {
              System.out.println("UserDaoImpl---->delete,id="+id);
          }
          @Override
          public List<String> select() {
              System.out.println("UserDaoImpl---->select...........");
              return Arrays.asList("111","222","333");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      /**
      * 静态代理
      * */
      public class UserStaticProxy implements UserDao {
          private UserDao userDao = null;
          public UserStaticProxy(UserDao userDao) {
              this.userDao = userDao;
          }
          @Override
          public void insert() {
              System.out.println("代理 增加的功能--->insert");
              userDao.insert();
          }
          @Override
          public void update() {
              System.out.println("代理 增加的功能--->update");
              userDao.update();
          }
          @Override
          public void delete(int id) {
              System.out.println("代理 增加的功能--->delete   id="+id);
              userDao.delete(id);
          }
          @Override
          public List<String> select() {
              System.out.println("代理 增加的功能--->select");
              return userDao.select();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      /**
      * 静态代理
      * */
      @Test
      public void StaticProxy(){
          UserStaticProxy userDaoProxy = new UserStaticProxy(new UserDaoImpl());
          userDaoProxy.insert();
          userDaoProxy.update();
          userDaoProxy.delete(10);
          List<String> list = userDaoProxy.select();
          System.out.println(list);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    动态代理

    • 动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的

    • 动态代理分为两类

      • 一类是基于接口动态代理----JDK动态代理
      • 一类是基于类的动态代理-----cglib
    • 一个动态代理 , 一般代理某一类业务,可以代理多个类,代理的是接口!

    • JdkProxy 实现方式

      public class JdkProxy implements InvocationHandler {
          /**
           * 执行被代理对象中的方法
           * @param proxy 被代理对象
           * @param method 目标方法
           * @param args 目标方法的参数值
           * @return 目标方法的返回值
           */
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("我是代理类添加的辅助业务。");
              //执行目标业务方法,利用反射
              Object result = method.invoke(targetClass.newInstance(), args);
              return result;
          }
          
          private Class targetClass;
          /**
           * 获取代理对象方法
           * 代理类对象:new JdbProxy(), 作用:生产代理对象
           * 代理对象:创建代理对象Proxy.newProxyInstance(),JDK代理对象实现了目标类接口的一个种对象
           */
          public Object getProxy(Class targetClass) {
              this.targetClass =targetClass;
              /*
               * newProxyInstance(loader,interfaces,this);生成代理对象
               * 三个参数分别如下
               * ClassLoader loader   :业务类的类加载器
               * Class[] interfaces:业务类实现的所有接口
               * InvocationHandler h  :代理类对象(此类)
               */
              //业务类的类加载器
              ClassLoader classLoader = targetClass.getClassLoader();
              //业务类实现的所有接口
              Class[] interfaces = this.targetClass.getInterfaces();
              //生成代理对象
              Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, this);
              return proxyObject;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
    • CglibProxy 实现方式

      /**
       * cglib动态代理
       * 对目标没有要求,普通类就可以,不用实现接口
       * 代理类是目标类的子类(父子继承)
       * */
      public class CglibProxy implements MethodInterceptor {
          /**
           * 执行目标方法
           * @param o 代理对象
           * @param method 目标方法对象
           * @param objects 目标方法参数值
           * @param methodProxy 代理方法的代理对象
           * @return 目标方法的返回值
           */
          @Override
          public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
              System.out.println("我是代理类添加的辅助业务。");
              //执行目标业务方法
              Object result = method.invoke(targetClass.newInstance(), objects);
              return result;
          }
          
          private Class targetClass;
          /**
           * 获取代理对象方法
           */
          public Object getProxy(Class targetClass) {
              this.targetClass =targetClass;
              Enhancer enhancer = new Enhancer();
              //目标对象设置为代理对象的父类
              enhancer.setSuperclass(targetClass);
              //设置回调,调用intercept方法
              enhancer.setCallback(this);
              return enhancer.create();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
    • 测试类

      /**
        * 动态代理
        * 两种方式,效果一样
        * */
      @Test
      public void JdkProxy(){
          //使用JdkProxy
      //	UserDao userDaoProxy = (UserDao) new JdkProxy().getProxy(UserDaoImpl.class);
          //使用CglibProxy
          UserDao userDaoProxy = (UserDao) new CglibProxy().getProxy(UserDaoImpl.class);
          userDaoProxy.insert();
          userDaoProxy.update();
          userDaoProxy.delete(100);
          System.out.println(userDaoProxy.select());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    AOP(面向切面)

    概念

    • 面向切面编程,是一种新的方法论,是对OOP面向对象编程的补充
    • 横切关注点:跨越应用程序多个模块的方法或功能。与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
    • 切面(Aspect):横切关注点,跨越多个模块的零散功能,组成的独立的、应用于其他模块之中的模块,是一个类
    • 通知(Advice):切面需要完成的工作,是类中的一个方法
    • 连接点(JoinPoint):某个程序的某个执行位置。例如:save()方法执行之前, update()方法执行之后
    • 切点(PointCut):多个模块的连接点组成为切点。例如:所有service类中的所有方法执行之前
    • 目标(Target):被通知对象
    • 代理(Proxy):向目标对象应用通知之后创建的对象
    • AOP的核心思想:在不改变原来的代码的情况下,实现了对原有功能的增强

    通知类型

    • 通知会根据连接点不同,分成以下四种通知,第五种是前四种的合成:
      1. 前置通知:方法执行之前
      2. 后置通知:方法执行之后。无法获取返回的数据
      3. 返回通知:方法返回数据之后,表示方法正常结束。可以获取返回的数据
      4. 异常通知:方法抛出异常之后,表示方法非正常结束。可以获取抛出的异常
      5. 环绕通知:以上四种通知的综合性通知

    简单实现AOP

    1. 引入依赖

      <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-aspectsartifactId>
          <version>5.3.21version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 切面类

      /**
       * 切面类,用来记录日志
       * 1.无需实现任何接口
       * 2.无需使用反射机制调用目标方法
       * 3.无侵入
       * */
      public class LogAspect {
          //JoinPoint对象封装了Aop中切面方法的信息
          public void beforeMethod(JoinPoint joinPoint){
              System.out.println("我是前置通知日志...");
          }
          public void afterMethod(JoinPoint joinPoint){
              System.out.println("我是后置通知日志...");
          }
          public void returnMethod(JoinPoint joinPoint,Object result){
              System.out.println("我是返回通知日志...返回值:"+result);
          }
          public void throwMethod(JoinPoint joinPoint,Exception e){
              System.out.println("我是异常通知日志...异常为:"+e.getMessage());
          }
          //环绕通知
          public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
              System.out.println("环绕通知的前置配置");
              try {
                  Object proceed = proceedingJoinPoint.proceed();
                  System.out.println("环绕通知的返回结果="+proceed);
              } catch (Throwable e) {
                  System.out.println("环绕通知的异常=" + e.getMessage());
              }
              System.out.println("环绕通知的后置配置");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
    3. 写applicationContext.xml

      • 
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:aop="http://www.springframework.org/schema/aop"
               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
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop.xsd">
            
        
            
            <bean id="user" class="com.dx.dao.impl.UserDaoImpl"/>
            <bean id="role" class="com.dx.dao.impl.RoleDaoImpl"/>
            <bean id="log" class="com.dx.aspect.LogAspect"/>
            
            <aop:config>
                
                <aop:pointcut id="exp" expression="execution(* com.dx.dao.impl.*.*(..))"/>
                
                <aop:aspect ref="log">
                    
                    <aop:before method="beforeMethod" pointcut="execution(* com.dx.dao.impl.*Impl.*(..))"/>
                    <aop:after method="afterMethod" pointcut-ref="exp"/>
                    <aop:after-returning method="returnMethod" returning="result"
                                         pointcut="execution(* com.dx.dao.impl.UserDaoImpl.select(..))"/>
                    <aop:after-throwing method="throwMethod" throwing="e"
                                         pointcut="execution(* com.dx.dao.impl.UserDaoImpl.delete(..))"/>
                    <aop:around method="aroundMethod" pointcut-ref="exp"/>
                aop:aspect>
            aop:config>
        beans>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
    • 说明
      • 切点表达式

               编写规则:execution()包裹
               1.单个方法
               语法:execution(方法访问修饰符 方法返回值类型 方法所在包名.方法所在类名.方法名(参数类型))
               例如:execution(public void com.bjpowernode.dao.impl.UserDaoImpl.insert())
               2.多个方法,通配符*
               语法:execution(* *.*.*(..))
               第一星不限制方法访问修饰符和返回值类型
               第二星不限制方法所在的包
               第三星不限制方法所在的类
               第四星不限制方法名称
               两个点不限制方法的参数
               例如:execution(* com.bjpowernode.dao.impl.UserDaoImpl.*(..))
               例如:execution(* com.bjpowernode.dao.impl.*Impl.*(..))
               例如:execution(* com.bjpowernode.*.service.impl.*Impl.*(..))
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      • 配置通知

        aop:before前置通知
        aop:after后置通知
        aop:after-returning返回通知
        aop:after-throwing异常通知
        属性:
            method: 切面对象的方法名称
            pointcut: 切点表达式, 将通知应用在那些方法上的一种表达式
            pointcut-ref: 切面表达式的引用
            returning: 是返回通知中的独有属性,配置接收方法的返回值参数
            throwing: 是异常通知中的独有属性,配置接收方法抛出异常对象
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

    使用注解实现

    • 切面类

      /**
       * 切面类
       * 使用注解配置
       * */
      @Aspect
      @Order(3)  //设置切面执行顺序
      public class OtherAspect {
          //配置一个公共的切面表达式,供其他注解调用
          @Pointcut("execution(* com.dx.dao.impl.*.*(..))")
          public void exp(){}
          
          @Before("execution(* com.dx.dao.impl.*.*(..))")
          public void before(){
              System.out.println("Other的------前置通知...");
          }
          @After("exp()")
          public void after(){
              System.out.println("Other的------后置通知日志...");
          }
      //    @AfterReturning
      //    @AfterThrowing
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    • applicationContext.xml

      
      <bean id="other" class="com.dx.aspect.OtherAspect"/>
      
      
      <aop:aspectj-autoproxy/>
      
      • 1
      • 2
      • 3
      • 4
      • 5

    多切面

    • 通知采用先进后出的原则
    • 前置通知先执行的切面,后置通知后执行
    • 可通过order属性配置切面的执行顺序,也可以使用@Order(1)注解
    • 属性值为整数类型,数字越小越优先
    • 在这里插入图片描述
    • <aop:aspect ref="other" order="2">
          <aop:before method="before" pointcut-ref="exp"/>
          <aop:after method="after" pointcut-ref="exp"/>
      aop:aspect>
      
      • 1
      • 2
      • 3
      • 4

    Spring与Mybatis整合

    1. 导入依赖

      
      <dependencies>
          <dependency>
              <groupId>org.springframeworkgroupId>
              <artifactId>spring-contextartifactId>
              <version>5.3.18version>
          dependency>
          
          <dependency>
              <groupId>org.springframeworkgroupId>
              <artifactId>spring-aspectsartifactId>
              <version>5.3.21version>
          dependency>
          
          <dependency>
              <groupId>org.mybatisgroupId>
              <artifactId>mybatis-springartifactId>
              <version>2.0.1version>
          dependency>
          <dependency>
              <groupId>mysqlgroupId>
              <artifactId>mysql-connector-javaartifactId>
              <version>8.0.19version>
          dependency>
          
          <dependency>
              <groupId>org.springframeworkgroupId>
              <artifactId>spring-jdbcartifactId>
              <version>5.3.4version>
          dependency>
          
          <dependency>
              <groupId>org.mybatisgroupId>
              <artifactId>mybatisartifactId>
              <version>3.5.1version>
          dependency>
          
          <dependency>
              <groupId>com.github.pagehelpergroupId>
              <artifactId>pagehelperartifactId>
              <version>5.2.0version>
          dependency>
          <dependency>
              <groupId>junitgroupId>
              <artifactId>junitartifactId>
              <version>4.13version>
              <scope>testscope>
          dependency>
          <dependency>
              <groupId>org.projectlombokgroupId>
              <artifactId>lombokartifactId>
              <version>1.18.24version>
          dependency>
          <dependency>
              <groupId>log4jgroupId>
              <artifactId>log4jartifactId>
              <version>1.2.17version>
          dependency>
      dependencies>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
    2. 配置文件

      • db.properties
        #mysql
        jdbc.mysql.driverClassName=com.mysql.cj.jdbc.Driver
        jdbc.mysql.url=jdbc:mysql://localhost:3306/student?serverTimezone=UTC
        jdbc.mysql.username=root
        jdbc.mysql.password=111111
        
        • 1
        • 2
        • 3
        • 4
        • 5
      • log4j.properties
        # 全局日志配置
        log4j.rootLogger=DEBUG, stdout
        # MyBatis 日志配置
        #局部日志记录配置
        log4j.logger.org.mybatis.example.BlogMapper=TRACE
        # 控制台输出
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
        log4j.appender.stdout.layout.ConversionPattern=%d %p %c.%M() --%m%n
        
        ### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
        log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
        log4j.appender.file.File = D:/logs/test.log
        #log4j.appender.file.Append = true
        #log4j.appender.file.Threshold = DEBUG
        log4j.appender.file.layout = org.apache.log4j.PatternLayout
        log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
        
        ### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
        log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
        log4j.appender.E.File =E://logs/error.log 
        log4j.appender.E.Append = true
        log4j.appender.E.Threshold = ERROR 
        log4j.appender.E.layout = org.apache.log4j.PatternLayout
        log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
    3. entity

      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class Emp {
          private Integer empno;
          private String ename;
          private String job;
          private Integer mgr;
          private Date hiredate;
          private Double sal;
          private Double comm;
          private Integer deptno;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    4. dao

      public interface EmpDao {
          List<Emp> select();
          Emp selectById(Integer empno);
          int insert(Emp entity);
          int update(Emp entity);
          int deleteById(Integer empno);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    5. EmpMapper.xml

      <mapper namespace="com.dx.dao.EmpDao">
          <select id="select" resultType="emp">
              select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno asc
          select>
          <select id="selectById" parameterType="int" resultType="Emp">
              select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=#{empno}
          select>
          <insert id="insert" parameterType="com.dx.entity.Emp">
              insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)
              values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})
          insert>
          <update id="update" parameterType="com.dx.entity.Emp">
              update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}
              where empno=#{empno}
          update>
          <delete id="deleteById" parameterType="int">
              delete from emp where empno=#{empno}
          delete>
      mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    6. mybatis-config.xml

      
      DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <settings>
              <setting name="mapUnderscoreToCamelCase" value="true"/>
              <setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
          settings>
          <typeAliases>
              <package name="com.dx.entity"/>
          typeAliases>
          <plugins>
              <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
          plugins>
      configuration>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    7. applicationContext.xml⭐

      
      <beans
      	xmlns="http://www.springframework.org/schema/beans"
      	xmlns:context="http://www.springframework.org/schema/context"
      	xmlns:aop="http://www.springframework.org/schema/aop"
      	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
      	http://www.springframework.org/schema/context
      	http://www.springframework.org/schema/context/spring-context.xsd
      	http://www.springframework.org/schema/aop
      	http://www.springframework.org/schema/aop/spring-aop.xsd">
      
      	
      	<context:component-scan base-package="com.dx"/>
      
      	
      	<context:property-placeholder location="classpath:db.properties"/>
      
      	
      	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      		<property name="driverClassName" value="${jdbc.mysql.driverClassName}"/>
      		<property name="url" value="${jdbc.mysql.url}"/>
      		<property name="username" value="${jdbc.mysql.username}"/>
      		<property name="password" value="${jdbc.mysql.password}"/>
      	bean>
      
      	
      	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      		
      		<property name="dataSource" ref="dataSource"/>
      		
      		<property name="configLocation" value="classpath:mybatis-config.xml"/>
      		
      		<property name="mapperLocations" value="classpath:mapper/*.xml"/>
      	bean>
      
      	
      	
      	<bean id="empDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
      		
      		<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
      		
      		<property name="mapperInterface" value="com.dx.dao.EmpDao"/>
      	bean>
      	
      	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      		
      		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
      		
      		<property name="basePackage" value="com.dx.dao"/>
      	bean>
      beans>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
    8. EmpController.java

      /**
       * 替代Serlvet
       * Controller web层:接收请求,处理请求,给予响应
       */
      @Controller
      public class EmpController {
          @Autowired
          private EmpService empService;
          public PageInfo<Emp> page(Integer pageNumber, Integer pageSize){
              return empService.page(pageNumber, pageSize);
          }
          public List<Emp> list(){
              return empService.list();
          }
          public Emp get(Integer empno){
              return empService.getById(empno);
          }
          public boolean save(Emp entity){
              return empService.save(entity);
          }
          public boolean edit(Emp entity){
              return empService.edit(entity);
          }
          public boolean remove(Integer empno){
              return empService.remove(empno);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
    9. 测试类

      @Test
      public void pageTest(){
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          EmpController empController = ac.getBean(EmpController.class);
          PageInfo<Emp> pageInfo = empController.page(2, 5);
          List<Emp> list = pageInfo.getList();
          for (Emp emp : list) {
              System.out.println(emp);
          }
          System.out.println("总页数:" + pageInfo.getPages());
          System.out.println("总记录数:" + pageInfo.getTotal());
      }
      @Test
      public void listTest(){
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          EmpController empController = ac.getBean(EmpController.class);
          List<Emp> list = empController.list();
          for (Emp emp : list) {
              System.out.println(emp);
          }
      }
      @Test
      public void insertTest(){
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          EmpController empController = ac.getBean(EmpController.class);
          Emp emp = new Emp(null,"小杨","经理",100,new Date(),6500.0,1000.0,10);
          boolean result = empController.save(emp);
          System.out.println(result);
      }
      @Test
      public void updateTest(){
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          EmpController empController = ac.getBean(EmpController.class);
          Emp emp = new Emp(7935,"小陈","经理",100,new Date(),6500.0,1000.0,10);
          boolean result = empController.edit(emp);
          System.out.println(result);
      }
      @Test
      public void deleteTest(){
          ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          EmpController empController = ac.getBean(EmpController.class);
          boolean result = empController.remove(7937);
          System.out.println(result);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44

    事务

    • 事务是一系列动作(执行SQL),一个事务是一个独立的不可拆分工作单元,事务中执行的所有SQL同时成功或同时失败
    • 事务的四个特性
      • 原子性 A
      • 一致性 C
      • 隔离性 I
      • 持久性 D

    编程式事务

    //设置关闭自动提交
    connection.setAutoCommit(false);
    try{
        //执行多个SQL语句
        ...
        connection.commit();
    }catch(Exception e){
        connection.rollback();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    声明式事务

    • 利用AOP来管理事务,由spring来实现事务的提交或回滚。

    • 声明式事务:1.配置事务管理器(切面)2.配置事务切入点

    • JDBC的事务管理器:DataSourceTransactionManager,它类似于一个切面

    • Hibernate的事务管理类器:HibernateTransactionManager

    事务属性

    1. 事务的传播性(propagation)
    • 当多个事务“相遇”(事务方法调用事务方法)时,spring该如何去处理。
    • REQUIRED: 如果一个事务方法调用另一个事务方法,那么两个方法中的事务会合二为一
    • REQUIRES_NEW:如果一个事务方法调用另一个事务方法,被调用事务方法会在自己独立的事务中运行
    • 在这里插入图片描述
    1. 事务隔离级别(isolation)
    • 数据库中自带的特性,在SQL标准中有四种:读未提交、读已提交、可重复读、可序列化。

    • 读未提交:读取其他事务没有提交的数据,读取其他事务的内存。会引起脏读、不可重复读、幻读。

    • 读已提交:仅能读取到其他事务提交的数据。可以避免脏读,但是会发生不可重复读、幻读。

    • 可重复读:在一个事务操作表时,将它操作的列锁定,使其他事务无法进行列的修改。可以避免脏读、不可重复读,但是会发生幻读。

    • 可序列化:在一个事务操作表时,将它操作的整个表锁定,使其他事务无法进行表的修改。可以避免所有的并发问题,但是效率低。

    • 事务并发出现的三种问题

      • 脏读:TX1读取了TX2的未提交的数据,此时TX2回滚了,那么TX1读取到的数据就是无效数据。
      • 不可重复读:TX读取了一个表中的字段值,再次读取时发现数据变化了。
      • 幻读:TX读取了表中记录数,再次读取时发现数据量变化了。
      • mysql数据库拥有以上四种事务隔离级别,默认的隔离级别是可重复读。
      • oracle数据库拥有读已提交和可序列化两种,默认的事务隔离级别为读已提交。
      • 注意:DEFAULT值表示spring的事务隔离级别配置,按照数据库默认隔离级别。
    1. 回滚列表,不回滚列表
    2. 只读事务
    3. 超时控制
      • 默认执行时间没有限制
      • 单位为秒
      • 如果在指定时间内事务没有执行完成,就是抛出异常,事务回滚

    事务的配置

    声明式事务

    • @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class Account {
          private Integer id;
          private String name;
          private Double balance;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • public interface AccountDao {
          void updateBalance(Account account);
          Account selectById(Integer id);
      }
      
      • 1
      • 2
      • 3
      • 4
      
      DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.dx.dao.AccountDao">
          <select id="selectById" parameterType="int" resultType="Account">
              select id, name, balance from account where id=#{id}
          select>
          <update id="updateBalance" parameterType="com.dx.entity.Account">
              update account set balance=#{balance} where id=#{id}
          update>
      mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • public interface AccountService {
          /*转账*/
          void transferMoney(Integer fromId, Integer toId, Double money) throws Exception;
      }
      
      • 1
      • 2
      • 3
      • 4
      @Service
      // @Transactional(rollbackFor = Exception.class)
      public class AccountServiceImpl implements AccountService {
          @Autowired
          private AccountDao accountDao;
          @Override
          public void transferMoney(Integer fromId, Integer toId, Double money) throws Exception {
              Account fromAccount = accountDao.selectById(fromId);
              Account toAccount = accountDao.selectById(toId);
              fromAccount.setBalance(fromAccount.getBalance()-money);
              accountDao.updateBalance(fromAccount);
              System.out.println("扣款成功");
              //模拟异常:Spring默认回滚的是运行时异常,可以在配置文件或注解中配置
      //        System.out.println(10/0);
              Class.forName("aaa");
              //事务超时,自动回滚
      //        Thread.sleep(5000);
              toAccount.setBalance(toAccount.getBalance()+money);
              accountDao.updateBalance(toAccount);
              System.out.println("转账完成");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    • 
      
      <tx:annotation-driven/>
      
      
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"/>
      bean>
      
      <tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
          <tx:attributes>
              
              <tx:method name="transferMoney" propagation="REQUIRES_NEW" isolation="DEFAULT" rollback-for="java.lang.Exception" timeout="4"/>
              
              <tx:method name="query*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="query*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="find*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="get*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="list*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="page*" rollback-for="java.lang.Exception" read-only="true"/>
              <tx:method name="add*" rollback-for="java.lang.Exception"/>
              <tx:method name="save*" rollback-for="java.lang.Exception"/>
              <tx:method name="insert*" rollback-for="java.lang.Exception"/>
              <tx:method name="edit*" rollback-for="java.lang.Exception"/>
              <tx:method name="update*" rollback-for="java.lang.Exception"/>
              <tx:method name="delete*" rollback-for="java.lang.Exception"/>
              <tx:method name="del*" rollback-for="java.lang.Exception"/>
              <tx:method name="remove*" rollback-for="java.lang.Exception"/>
              <tx:method name="*"/>
          tx:attributes>
      tx:advice>
      
      <aop:config>
          <aop:pointcut id="exp" expression="execution(* com.dx.service.impl.*Impl.*(..))"/>
          <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="exp"/>
      aop:config>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

    注解式事务

    • public interface AccountService {
          /*多商品一起付款*/
          void payOrder(Integer fromId, Map<Integer,Double> map) throws Exception;
      }
      
      • 1
      • 2
      • 3
      • 4
      @Service
      @Transactional(rollbackFor = Exception.class)
      public class AccountServiceImpl implements AccountService {
          //注入自己
          @Autowired
          private AccountService accountService;
          @Override
          public void transferMoney(Integer fromId, Integer toId, Double money) throws Exception {
              Account fromAccount = accountDao.selectById(fromId);
              Account toAccount = accountDao.selectById(toId);
              fromAccount.setBalance(fromAccount.getBalance()-money);
              accountDao.updateBalance(fromAccount);
              System.out.println("扣款成功");
              toAccount.setBalance(toAccount.getBalance()+money);
              accountDao.updateBalance(toAccount);
              System.out.println("转账完成");
          }
          @Override
          //注解式事务
          @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED,
                  rollbackFor = Exception.class, rollbackForClassName = "java.lang.Exception",
                  readOnly = true, timeout = 5)
          public void payOrder(Integer fromId, Map<Integer, Double> map) throws Exception {
              Set<Integer> toIdSet = map.keySet();
              System.out.println(toIdSet.size());
              for (Integer toId : toIdSet) {
                  System.out.println("toId="+toId);
                  double money = map.get(toId);
                  accountService.transferMoney(fromId,toId,money);
                  //模拟异常
                  String s=null;
                  s.trim();
              }
              System.out.println("订单支付成功");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
    • 
      <tx:annotation-driven/>
      
      • 1
      • 2

    mId, Map map) throws Exception;
    }

    
    ```java
    @Service
    @Transactional(rollbackFor = Exception.class)
    public class AccountServiceImpl implements AccountService {
        //注入自己
        @Autowired
        private AccountService accountService;
        @Override
        public void transferMoney(Integer fromId, Integer toId, Double money) throws Exception {
            Account fromAccount = accountDao.selectById(fromId);
            Account toAccount = accountDao.selectById(toId);
            fromAccount.setBalance(fromAccount.getBalance()-money);
            accountDao.updateBalance(fromAccount);
            System.out.println("扣款成功");
            toAccount.setBalance(toAccount.getBalance()+money);
            accountDao.updateBalance(toAccount);
            System.out.println("转账完成");
        }
        @Override
        //注解式事务
        @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED,
                rollbackFor = Exception.class, rollbackForClassName = "java.lang.Exception",
                readOnly = true, timeout = 5)
        public void payOrder(Integer fromId, Map map) throws Exception {
            Set toIdSet = map.keySet();
            System.out.println(toIdSet.size());
            for (Integer toId : toIdSet) {
                System.out.println("toId="+toId);
                double money = map.get(toId);
                accountService.transferMoney(fromId,toId,money);
                //模拟异常
                String s=null;
                s.trim();
            }
            System.out.println("订单支付成功");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 
      <tx:annotation-driven/>
      
      • 1
      • 2
  • 相关阅读:
    如何学好次世代角色建模?
    Notebook系列第12期:如何使用异步API来提升模型推理性能
    机器人工程相关课程共性问题的思考-2022-
    Java,常用类与API,比较器与其他常用类的使用
    count(1)、count(*)、count(id)、count(name)区别
    Docker介绍
    Mysql执行报错:[Err] 1292 - Truncated incorrect DOUBLE value:***
    数据可视化新秀 DataEase 可否替代 Tableau?
    numpy基础——对array的切片、矩阵加法乘法
    【数据分享】2008-2022年全国范围逐年NO2栅格数据(免费获取)
  • 原文地址:https://blog.csdn.net/qq_43528471/article/details/125887936