Spring

简介

  • Spring :春天,给软件行业带来了春天

  • 2002,首次推出了Spring框架的雏形,interface21框架

  • 2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版本。

  • Spring概念:使现有的技术更加容易使用,本身是个大杂烩,整合现有的技术框架

  • SSH: Struct2 + Spring + Hibernate

  • SSM:SpringMVC +Spring+MyBatis

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

  • 官网 : http://spring.io/

  • 官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

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

  • <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.12.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.12.RELEASE</version>
    </dependency>
    

优点

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

总结

  • Spring 就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

组成

组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。模块功能如下:

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

拓展

  • 在Spring的官网有这个介绍,现代化的java开发!说白了就是基于Spring的开发

  • Spring boot
    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速开发的单个微服务
    • 约定大于配置
  • Spring Cloud
    • SpringCloud 是基于SpringBoot实现的

IOC理论推导

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

    @Override
    public void getUser() {
        userDao.getUser();
    }
 public static void main(String[] args) {
        UserServiceImpl service = new UserServiceImpl();
        service.setUserDao( new UserDaoMySqlImpl() );
        service.getUser();
       
        service.setUserDao( new UserDaoOracleImpl() );
        service.getUser();

    }
  • 这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

IOC 本质

  • 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

  • IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现Ioc
  • Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
  • 控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的.
  • 反转:程序本身不创建对象,而变成被动的接收对象.
  • 依赖注入:就是利用set方法来进行注入的.
  • I0C是一种编程思想,由主动的编程变成被动的接收.
  • 可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .
  • 不用在程序中去改动了,要实现不同的操作,只需要在xm|配置文件中进行修改,所谓的IoC:对象由Spring来创建,管理,装配!

ioc 创建对象的方式

  1. 使用无参构造创建对象,默认

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

  3. <bean id="hello" class="com.liu.pojo.Hello">
      <!--  下标赋值-->
       <constructor-arg index="0" value="dfds"/>
      <!--  通过类型创建,不建议使用 -->
     	<constructor-arg type="java.lang.String" value="fhadsfakdfhka"/>
      <!--  通过参数名-->
      <constructor-arg name="str" value="aa"/>
    </bean>
    
  4. 在配置文件加载的时候,容器中管理的对象,已经初始化了

Spring 配置

  • 别名

    • <!--别名 -->
      <alias name="hello" alias="hello2"/>
      
  • Bean配置

  • <!--
        id:bean 的唯一标识符,对象名
        class:bean 对象所对应的全限定名:包名 + 类型
        name:也是别名,而且那么可以同时取多个别名
     -->
    <bean id="hello" class="com.liu.pojo.Hello">
        <constructor-arg name="str" value="aa"/>
    </bean>
    
  • import

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

依赖注入

  • 构造器注入

    • 依赖不可变:其实说的就是final关键字,写法就是(private final Service service;)
    • 依赖不为空:当实例化Controller的时候,由于自己实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数。
  • Set方式注入(*****)

    • 依赖注入:Set注入

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

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

    • 【环境搭建 】

      • package com.liu.pojo;
        
        public class Address {
            private  String address;
        
            public Address() {
            }
        
            public Address(String address) {
                this.address = address;
            }
        
            public String getAddress() {
                return address;
            }
        
            public void setAddress(String address) {
                this.address = address;
            }
        
            @Override
            public String toString() {
                return "Address{" +
                        "address='" + address + '\'' +
                        '}';
            }
        }
        
    • 真是测试对象

    • package com.liu.pojo;
      
      import java.util.*;
      
      public class Students {
      
          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;
      
          public Students() {
          }
      
          public Students(String name, Address address, String[] books, List<String> hobbys, Map<String, String> card, Set<String> games, String wife, Properties info) {
              this.name = name;
              this.address = address;
              Books = books;
              this.hobbys = hobbys;
              this.card = card;
              this.games = games;
              this.wife = wife;
              this.info = info;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Address getAddress() {
              return address;
          }
      
          public void setAddress(Address address) {
              this.address = address;
          }
      
          public String[] getBooks() {
              return Books;
          }
      
          public void setBooks(String[] books) {
              Books = books;
          }
      
          public List<String> getHobbys() {
              return hobbys;
          }
      
          public void setHobbys(List<String> hobbys) {
              this.hobbys = hobbys;
          }
      
          public Map<String, String> getCard() {
              return card;
          }
      
          public void setCard(Map<String, String> card) {
              this.card = card;
          }
      
          public Set<String> getGames() {
              return games;
          }
      
          public void setGames(Set<String> games) {
              this.games = games;
          }
      
          public String getWife() {
              return wife;
          }
      
          public void setWife(String wife) {
              this.wife = wife;
          }
      
          public Properties getInfo() {
              return info;
          }
      
          public void setInfo(Properties info) {
              this.info = info;
          }
      
          @Override
          public String toString() {
              return "Students{" +
                      "name='" + name + '\'' +
                      ", address=" + address.toString()) +
                      ", Books=" + Arrays.toString(Books) +
                      ", hobbys=" + hobbys +
                      ", card=" + card +
                      ", games=" + games +
                      ", wife='" + wife + '\'' +
                      ", info=" + info +
                      '}';
          }
      }
      
    • beans.xml

    • <<?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="address" class="com.liu.pojo.Address">
              <property name="address" value="北京"/>
          </bean>
          <bean id="student" class="com.liu.pojo.Students">
              <!-- 第一种,普通 值注入  -->
              <property name="name" value="lium"/>
              <!-- 第二种,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>list1</value>
                      <value>list2</value>
                      <value>list3</value>
                  </list>
              </property>
              <!-- map 注入   -->
              <property name="card">
                  <map>
                      <entry key="手机号" value="1111"/>
                      <entry key="电话" value="22222"/>
                  </map>
              </property>
              <!-- set 注入   -->
              <property name="games">
                  <set>
                      <value>abcdefg</value>
                      <value>abcdefg111</value>
                      <value>abcdefg222</value>
                  </set>
              </property>
              <!-- null 注入   -->
              <property name="wife">
                  <null/>
              </property>
              <!-- Properties 注入   -->
              <property name="info">
                  <props>
                      <prop key="学号1">s00001</prop>
                      <prop key="学号2">s00002</prop>
                      <prop key="学号3">s00003</prop>
                  </props>
              </property>
          </bean>
      </beans>
      
    • 测试类

    • import com.liu.pojo.Students;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class StudentsTest {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
              Students student = (Students) context.getBean("student");
              System.out.println(student.toString());
          }
      }
      

bean 的作用域

  • 代理模式(Spring 默认机制)

    • <bean id="address" class="com.liu.pojo.Address" scope="singleton">
          <property name="address" value="北京"/>
      </bean>
      
  • 原型模式 每次从容器中get 的时候,都会产生一个新对象

    • <bean id="address" class="com.liu.pojo.Address" scope="singleton">
          <property name="address" value="北京"/>
      </bean>
      
  • 其余的 request session application 这些个只能在web 开发中使用到

Bean 的自动装配

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

在Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在java中显示的配置
  3. 隐式的自动装配bean(***********)

ByName 自动装配

<!--
byName: 会自动在容器的上下文查找和自己对象set方法后面的值对象的 bean id
   -->
<bean id="people" class="com.liu.pojo.People" autowire="byName">
    <property name="name" value="liu"/>
</bean>

byType

<!--
byName: 会自动在容器的上下文查找 和自己对象set方法后面的值对象的 bean id
byType: 会自动在容器的上下文查找 和自己对象属性类型相同的bean
   -->
<bean id="people" class="com.liu.pojo.People" autowire="byType">
    <property name="name" value="liu"/>
</bean>
  • byName:需要保证bean 的id唯一,并且bean需要和自动注入的属性的set方法一致
  • byType:需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性类型一致

使用注解实现自动装配

  • JDK 1.5 支持的注解

  • Spring 2.5 支持了注解

  • 要使用注解须知

    • 导入约束 context 约束

    • 配置注解的支持 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>
      
  • @Autowired

    • 直接在属性上使用,也可以在set方式上使用

    • 使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byName

    • @Nullable 字段标记了这个注解,可以为null
      
    • public @interface Autowired {
          boolean required() default true;
      }
      
    • public class People {
      		//如果现实定义了Autowired 的required 属性为false,说明这个对象可以为null,否则不允许为空
          @Autowired(required = false)
          private Cat cat;
          @Autowired
          private Dog dog;
          private String name;
      }
      
    • 如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,可以使用@Qualifier(value = "XX") 去配置@Autowired的使用,置顶一个唯一的bean 对象注入

    • @Resource 注解 和Autowired 的区别

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

使用注解开发

  • 在Spring4.0之后,要使用注解开发,必须要保证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:annotation-config/>  
</beans>

bean

使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!

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

属性如何注入

  • 可以不用提供set方法,直接在直接名上添加@value("值")

  • 如果提供了set方法,在set方法上添加@value("值");

  • 衍生的注解

  • @Component 有几个衍生注解,在web开发中,会安装MVC三层架构分层

    • dao【@Repository】
    • service【@Service】
    • controller【@Controller】
    • 这四个注解功能都一样,都是代表某个类注册到Spring中,装配bean

自动装配置

  • @Autowired :自动装配通过类型,名字,如果Autowired补鞥呢唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
  • @Nullable :字段标记了这个注解,说明这个字段可以为null
  • @Resource 自动装配通过名字,类型

作用域

@Component
@Scope("prototype")
public class User {

    @Value("llll")
    public String name;
}

总结

  • xml 与注解

    • xml 更加万能,适合任何场合,维护方便
    • 注解:不是自己的类使用不了,维护相对复杂
  • xml 与注解最佳实践:

    • xml用来管理bean

    • 注解只负责完成属性的注入

    • 在使用的过程,只需要注意一个问题,必须让注解剩下,就需要开启注解的支持

    • <!-- 指定要扫描的包,这个包下的注解就会生效 -->
      <context:component-scan base-package="com.liu.pojo"/>
      
      <context:annotation-config/>
      

使用java的方式配置 Spring

  • 完全不是用Spring的xml 配置了,全权交给了java来做
  • JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
//实体类
@Component  //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
    public String name = "dog";
}

//config配置
@Configuration  //代表这是一个配置类
public class MyConfig {
 
    @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
    public Dog dog(){
        return new Dog();
    }
}

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

纯java的配置方式,在SpringBoot 中随处可见

代理模式

  • 为啥要学代理模式?因为这既是SpringAOP的底层【SpringAOP 和Apring MVC】
  • 代理模式的好处
    • 可以使真是角色的操作更加纯粹,不用去关注一些公共业务
    • 公共业务也交给了代理角色,实现了业务的分工
    • 公共业务发生扩展的时候,方便集中管理
    • 一个动态代理类代理是一个接口,一般就是对应的一类业务
    • 一个动态代理可以代理多个类,只要是实现了同一个接口
  • 缺点
    • 一个真是角色就会产生一个代理角色:代码量会翻倍,开发效率变低
  • 代理模式的分类
    • 静态代理
      • 角色分析:
        • 抽象角色:一般会使用接口活抽象类
        • 真是角色:被代理的角色
        • 代理角色:代理真实角色,代理真是角色后,我们一般会做一些附属操作
        • 客户:访问代理的角色
    • 动态代理
      • 动态代理和静态代理角色一样
      • 动态代理的代理类是动态生成的,不是我们直接写好的!
      • 动态代理分为两大类
        • 基于接口的动态代理
          • JDK动态代理
        • 基于类的动态代理
          • cglib
        • java字节码实现:javasist
      • 需要了解两个类:
        • Proxy 代理
        • InvocationHandler 调用处理程序
public class ProxyInvocationHandler implements InvocationHandler {
    private Rent rent;
 
    public void setRent(Rent rent) {
        this.rent = rent;
    }
 
    //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(),this);
    }
 
    // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
    // 处理代理实例上的方法调用并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //核心:本质利用反射实现!
        Object result = method.invoke(rent, args);
        fare();
        return result;
    }
 
    public void seeHouse(){
        System.out.println("带房客看房");
    }
    public void fare(){
        System.out.println("收中介费");
    }
  
public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        //代理实例的调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setRent(host); //将真实角色放置进去!
        Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
        proxy.rent();
    }

AOP

什么是AOP?

  • AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Aop 在Spring中的作用

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

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

使用Spring 实现 AOP

  • 【重点】使用AOP织入,需要导入一个依赖包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>
  • 使用Spring的APi接口【主要SpringApi接口实现】
  • 自定义来实现AOP【主要是切面定义】
  • 使用注解来实现

整合Mybatis

  • 步骤

    • 导入相关jar包

      • Junit

      • mybatis

      • mysql数据库

      • Spring相关的

      • aop织入

      • mybatis-spring【new】

        • <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis-spring</artifactId>
              <version>2.0.6</version>
          </dependency>
          
          
  • 编写配置文件

  • 测试

mybatis-spring

UserMapper

package com.liu.mapper;

import com.liu.pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> selectUser();
}

UserMapper.xml

<?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">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.liu.mapper.UserMapper">

    <!--select查询语句-->
    <select id="selectUser" resultType="User">
        select * from sys_user limit 10
    </select>
</mapper>

UserMapperImpl

package com.liu.mapper;

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

import java.util.List;

public class UserMapperImpl implements UserMapper {
    //所有的操作,都使用SqlSession来执行,在原来,现在都用SqlSessionTempLate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

实体类

package com.liu.pojo;

import lombok.Data;

@Data
public class User {
    private int UserId;
    private String WorkNum;
    private String Mobile;
    private String NickName;
    private String UserPwd;
    private int OrgId;
    private String OrgIds;
}

applicationContext.xml

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

    <!-- -->
    <bean id="userMapper" class="com.liu.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

</beans>

mybatis-config.xml

<?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核心配置文件-->
<configuration>
    <typeAliases>
        <package name="com.liu.pojo"/>
    </typeAliases>

    <!--  设置  -->
</configuration>

spring-dao.xml

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

    <!--DataSource : 使用Spring 的数据源替换mybatis的配置-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://xxxx:3306/xxxx?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC

"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </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/liu/mapper/*.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用够着去注入sqlSessionFactory,因为没有set 方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
  
  
    <!-- 配置声明式事务 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource"/>
    </bean>

    <!-- 结合AOP  -->
    <!-- 配置事务的类   -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 给那些方法配置事务  -->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete"/>
            <tx:method name="update"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.liu.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
  
</beans>

测试

import com.liu.mapper.UserMapper;
import com.liu.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.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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


public class MyTest {

    @Test
    public void testUser() throws IOException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = applicationContext.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }
}

声明式事务

事务

  • 要么都成功,要么都失败
  • 事务在项目开发中非常重要,涉及到数据的一直行问题
  • 确保完整性和一直性

事务ACID原则

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源,防止数据损坏
  • 持久性
    • 事务一但提交,无论系统发生什么问题,结果都不会再被影响 ,被持久化的写存储器中

spring中的事务管理

  • 声明式事务:AOP
  • 编程式事务:需要在代码中进行事务的管理
posted @ 2021-01-31 21:08  流年りゅう  阅读(373)  评论(0)    收藏  举报