Spring5框架学习笔记(详细)
阅读原文时间:2023年07月09日阅读:1

目录

01 Spring框架概述

02 IOC容器

IOC概念和原理

IOC BeanFactory接口

IOC操作 Bean管理(概念)

IOC操作 Bean管理(基于xml方式)

IOC操作 Bean管理(bean作用域)

IOC操作 Bean管理(bean生命周期)

IOC操作 Bean 管理(xml 自动装配)

IOC操作 Bean 管理(外部属性文件)

IOC操作 Bean管理 (基于注解方式)

03 AOP

AOP概念

AOP(底层原理)

AOP操作(准备工作)

AOP操作(AspectJ 注解)

AOP操作(AspectJ 配置xml文件)

04 JdbcTemlate

JdbcTemplate(概念和准备)

JdbcTemplate操作数据库(添加,修改,删除)

JdbcTemplate操作数据库(查询返回某个值,对象,集合)

JdbcTemplate操作数据库(批量添加、修改、删除)

05 事务管理

事务操作(事务概念)

事务操作(Spring事务管理介绍)

事务操作(使用注解配置声明式事务管理)

事务操作(使用xml配置声明式事务管理)

事务操作(完全注解配置声明式事务管理)

06 Spring5新特性

07 Spring5框架新功能(Webflux)


01 Spring框架概述

  • Spring是轻量级的开源的JavaEE框架

  • Spring可以解决企业应用开发的复杂性

  • Spring有两个核心部分:IOC和AOP

    • IOC(Inversion of Control),控制反转,把创建对象过程交给Spring进行管理
    • AOP(Aspect Oriented Programming),面向切面编程,不修改源代码进行功能增强
  • Spring特点:

    • 方便解耦,简化开发
    • AOP编程支持
    • 方便程序测试
    • 方便和其他框架整合
    • 方便进行事务操作
    • 降低API开发难度
  • 使用Spring5最新稳定版5.2.6,https://repo.spring.io/release/org/springframework/spring/

    入门案例

    创建一个普通类,有一个普通方法

    public class User {
    public void add() {
    System.out.println("add…..");
    }
    }

    创建xml配置文件


    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>

    使用spring创建对象

    public class TestUser {
    @Test
    public void test1() {
    ApplicationContext context
    = new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user", User.class);
    System.out.println(user);
    user.add();
    }
    }

02 IOC容器

  • 什么是IOC:控制反转,把对象创建和对象直接的调用过程交给Spring进行管理;使用IOC的目的是为了降低耦合度;入门案例就是IOC的实现

  • IOC底层原理:xml解析、工厂模式、反射,a类中调用b类对象的方法时,a类通过调用工厂类的方法获得b类对象,进而调用方法,在工厂类中,通过xml解析获取到类的class,通过反射创建b类对象,降低了a类和b类的耦合,当b类的类路径改变时,工厂类一样可以正常返回b类对象

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

  • Spring提供IOC容器的两种实现方式(两个接口)

    • BeanFactory,IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    • ApplicationContext,BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建
  • ApplicationContext有接口实现类

    • FileSystemXmlApplicationContext
    • ClassPathXmlApplicationContext
  • 什么是Bean管理,指两个操作,Spring创建对象,Spring注入属性

  • Bean管理的两种方式,基于xml配置文件方式实现基于注解方式实现

  • Spring有两种bean,一种普通bean,另外一种工厂bean(FactoryBean)

    • 普通bean:在配置文件中定义bean类型就是返回类型
    • 工厂bean:在配置文件定义bean类型可以和返回类型不一样,实现FactoryBean接口,重写方法,定义返回类型
  • 创建对象:在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建,id属性,class属性,name属性(可以有其他字符);默认执行无参构造方法

  • 注入属性,(Dependency Injection,DI)

    • 使用set方法注入,创建类,定义属性和对应的set方法,在spring配置文件中配置对象创建,配置属性注入
    • 使用有参构造方法注入,创建类,定义属性,创建属性对应有参数构造方法,在spring配置文件中进行配置
    • p名称空间注入,set方法注入的简化,需要配置名称空间p
    • 注入null值和特殊符号
    • 注入属性:外部bean,使用ref标签
    • 注入属性:内部bean,在bean内部创建bean
    • 注入属性:级联赋值,需要设置get方法获得对象才能级联赋值
    • 注入属性:集合属性,数组、List、Map、Set
  • 使用util标签提取,需要配置util命名空间


    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>
    
    <!--基于xml方式set方法注入属性-->
    <bean id="book" class="com.atguigu.spring5.Book">
        <property name="bname" value="书名"></property>
        <property name="bauthor" value="作者"></property>
    </bean>
    
    <!--基于xml方式有残参构造方法注入属性-->
    <bean id="orders" class="com.atguigu.spring5.Orders">
        <constructor-arg name="oname" value="电脑"></constructor-arg>
        <constructor-arg name="address" value="China"></constructor-arg>
    </bean>
    
    <!--p名称空间注入属性-->
    <bean id="bookp" class="com.atguigu.spring5.Book" p:bname="书名p" p:bauthor="作者p">
    
    <!--注入null值和特殊符号-->
    <bean id="booknull" class="com.atguigu.spring5.Book">
        <property name="bname">
            <null/>
        </property>


    <!--注入属性-外部bean-->
    <bean id="userDaoImp" class="com.atguigu.spring5.dao.UserDaoImp"></bean>
    <bean id="userService" class="com.atguigu.spring5.service.UserService">
        <property name="userDao" ref="userDaoImp"></property>
    </bean>
    
    <!--注入属性-内部bean-->
    <bean id="userService2" class="com.atguigu.spring5.service.UserService">
        <property name="userDao">
            <bean id="userDaoImp2" class="com.atguigu.spring5.dao.UserDaoImp"></bean>
        </property>
    </bean>
    
    <!--级联赋值-需要设置get方法获得对象-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="name" value="emp1"></property>
        <property name="dept" ref="dept1"></property>
        <property name="dept.dName" value="Dept1"></property>
    </bean>
    <bean id="dept1" class="com.atguigu.spring5.bean.Dept">
        <property name="dName" value="Dept1"></property>
    </bean>
    
    <!--注入集合属性-->
    <bean id="courseOut1" class="com.atguigu.spring5.bean.Course">
        <property name="name" value="OutBean"></property>
    </bean>
    <bean id="stu" class="com.atguigu.spring5.bean.Stu">
        <property name="courses">
            <array>
                <value>course1</value>
                <value>course2</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        <property name="courseList">
            <list>
                <bean id="course1" class="com.atguigu.spring5.bean.Course">
                    <property name="name" value="English"></property>
                </bean>
                <bean id="course2" class="com.atguigu.spring5.bean.Course">
                    <property name="name" value="Chinese"></property>
                </bean>
                <ref bean="courseOut1"></ref>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="k1" value="v1"></entry>
                <entry key="k2" value="v2"></entry>
            </map>
        </property>
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
    </bean>
    
    <!--提取集合属性,以List为例,需要修改命名空间-->
    <util:list id="courseList2">
        <bean id="course1" class="com.atguigu.spring5.bean.Course">
            <property name="name" value="English2"></property>
        </bean>
        <bean id="course2" class="com.atguigu.spring5.bean.Course">
            <property name="name" value="Chinese2"></property>
        </bean>
        <ref bean="courseOut1"></ref>
    </util:list>
    <bean id="stu2" class="com.atguigu.spring5.bean.Stu">
        <property name="courseList" ref="courseList2"></property>
    </bean>

  • 在Spring里面,设置创建bean实例是单实例还是多实例,默认情况下,bean是单实例对象

  • 创建对象时使用scope配置是但例还是多例,singletonprototype,request,session

  • 区别:一个单例,一个多例,单例在加载配置文件时就已经创建好对象了,多例是在getBean时创建

  • 通过无参构造器创建bean实例

  • 调用set方法设置bean的属性值和其他bean引用

  • 调用初始化方法,初始化之前会调用后置处理器中的postProcessBeforeInitialization()方法,初始化之后也调用postProcessAfterInitialization()方法

    • bean中使用init-method配置初始化方法
    • 后置处理器需要实现BeanPostProcessor接口,里面有两个默认方法,在xml中配置为一个bean就可以了,会对xml中所有的bea应用后置处理器
  • 获取到对象,可以使用

  • 容器关闭时,调用bean的销毁方法

    • bean中使用destroy-method配置销毁方法,在使用时手动调用context.close()

  • 根据指定装配规则(名称或者类型),Spring自动将匹配的属性值进行注入

  • byName:属性名与bean id相同,byType:根据bean的类型匹配,必须只有一个同类型的

    <!--自动注入-autowire="byName" - "byType"-->
    <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"></bean>
    <bean id="dept" class="com.atguigu.spring5.autowire.Dept">
        <property name="dname" value="deptA"></property>
    </bean>
  • 引入外部.properties文件,需要配置名称空间context


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

    <!--直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    
    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="url" value="${prop.url}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>

    jdbc.properties

    prop.driverClass=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/userDb
    prop.username=root
    prop.password=root

  • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)

  • 使用注解的目的:简化xml配置

  • Spring中针对Bean管理创建对象提供4个注解:@Component,@Service,@Controller,@Repository,功能一样,都可以创建注解

  • 创建对象

    • 导入依赖aop.jar
    • 开启组件扫描,多个包逗号隔开,或者使用包的上层目录,需要配置context命名空间
    • 创建类,在类上面添加创建类的注解,默认的bean名是类首字母小写
    • 只扫描某一部分,或排除扫描某一部分


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

    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
    
    <!--示例1
    use-default-filters="false" 表示不扫描所有,
    自己配置扫描的内容filter context:include-filter -->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan> 
    
    <!--示例2
    扫描包所有内容 context:exclude-filter
    自己配置哪些内容不进行扫描 -->
    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    @Component("userService")
    public class UserService {
    public void add() {
    System.out.println("service add…");
    }
    }

  • 属性注入

    • @Autowired,根据类型自动装配,多个同类型的则匹配name
    • @Qualifier:根据名称进行注入,需要跟@Autowired一起使用
    • @Resource:可以根据类型注入,可以根据名称注入
    • @Value:注入普通类型属性
  • 完全注解开发,使用配置类替代xml的组件扫描

    public interface UserDao {
    public void add();
    }

    @Repository //默认名称类首字母小写
    public class UserDaoImp implements UserDao {
    @Override
    public void add() {
    System.out.println("add…");
    }
    }

    @Service("userService")
    public class UserService {
    @Autowired //自动根据类型注入
    @Qualifier("userDaoImp") //根据名称注入
    private UserDao userDao;

    // @Resource //根据类型注入
    @Resource(name = "userDaoImp") //根据名称注入
    private UserDao userDao;

    @Value(value = "hello") //注入普通类型
    private String a;
    
    public void add() {
        System.out.println("service add..." + a);
        userDao.add();
    }

    }

    完全注解开发

    @Configuration //作为配置类,提到xml配置文件
    @ComponentScan(basePackages = {"com.atguigu.spring5"})
    public class SpringConf {
    }

    测试类

    public class TestDemo {

    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
    
    @Test
    public void test2() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConf.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }

    }

03 AOP

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

  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

  • 术语:

    • 连接点,类里面可以被增强的方法称为连接点
    • 切入点,实际被增强的方法称为切入点
    • 通知(增强),实际增强的逻辑部分称为通知,前置通知,后置通知,环绕通知,异常通知,最终通知
    • 切面,将通知应用到切入点的过程称为切面
  • AOP底层使用动态代理

    • 第一种 有接口情况,使用JDK动态代理,创建接口实现类代理对象,增强类的方法
    • 第二种 没有接口情况,使用CGLIB(Code Generation Library)动态代理,创建子类的代理对象,增强类的方法
  • JDK动态代理

    接口

    public interface UserDao {
    public int add(int a, int b);
    public void update(String s);
    }

    实现类

    public class UserDaoImp implements UserDao {
    public String[] sa = {"1", "2"};

    @Override
    public int add(int a, int b) {
        System.out.println("add()...");
        return a + b;
    }
    
    @Override
    public void update(String s) {
        System.out.println(s);
    }
    
    public String[] getSa() {
        return sa;
    }

    }

    代理类

    public class JDKProxy {
    public static void main(String[] args) {
    //创建接口实现类代理对象
    Class[] interfaces = {UserDao.class};
    UserDaoImp userDaoImp = new UserDaoImp();
    UserDao userDao = (UserDao) Proxy.newProxyInstance(UserDaoImp.class.getClassLoader(), interfaces,
    new UserDaoProxy(userDaoImp));

        //测试
        int add = userDao.add(1, 2);//使用代理类对象调用,会传给InvocationHandler,调用被代理类对象的方法
        userDao.update("hello");

    // userDao.getSa(); //无法调用,只代理接口中的方法

    }

    }

    class UserDaoProxy implements InvocationHandler {
    private Object object;

    public UserDaoProxy(Object object) {
        this.object = object;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("before invocation...");
    Object res = method.invoke(object, args); //被代理类对象及其参数
    System.out.println("after invocation... + res: " + res); //没有返回值返回null
    return res;
    }

    }

  • Spring框架一般都是基于AspectJ实现AOP操作,)AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作

  • 基于AspectJ实现AOP操作:基于xml配置文件方式基于注解方式

  • 切入点表达式

    • 作用:知道对哪个类里面的哪个方法进行增强
    • 语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )

    举例1:对com.atguigu.dao.BookDao类里面的add进行增强
    execution(* com.atguigu.dao.BookDao.add(..))
    举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
    execution(* com.atguigu.dao.BookDao.* (..))
    举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
    execution(* com.atguigu.dao.. (..))

  • 导入相关依赖

    • com.springsource.net.sf.cglib-2.2.0.jar
    • com.springsource.org.aopalliance-1.0.0.jar
    • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • spring-aspects-5.2.6.RELEASE.jar

    //被增强的类
    @Component //使用注解创建对象
    public class User {
    public void add() {
    System.out.println("add…");
    // throw new RuntimeException();
    }
    }

    //增强的类
    @Component //使用注解创建对象
    @Aspect //生成代理对象
    @Order(1) //有多个增强类对同一个方法进行增强,设置增强类优先级,数字越小优先级越高
    public class UserProxy {

    //相同切入点抽取
    @Pointcut("execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void pointDemo() {}
    
    //@Before表示前置通知,增强User.add()方法
    @Before(value = "pointDemo()") //使用相同切入点抽取的方法pointDemo()
    public void before() {
        System.out.println("before...");
    }
    
    //@AfterReturning表示后置通知,增强User.add()方法
    @AfterReturning(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning...");
    }
    
    //@After表示最终通知,增强User.add()方法
    @After(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void after() {
        System.out.println("after...");
    }
    
    //@AfterThrowing表示异常通知,增强User.add()方法
    @AfterThrowing(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing...");
    }
    
    //@Around表示环绕通知,增强User.add()方法
    @Around(value = "execution(* com.atguigu.spring5.aopAnnotation.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后");
    }

    }

    //多个增强类设置优先级
    @Component //使用注解创建对象
    @Aspect //生成代理对象
    @Order(2) //有多个增强类多同一个方法进行增强,设置增强类优先级,数字越小优先级越高
    public class UserProxy2 {
    //@Before表示前置通知,增强User.add()方法
    @Before(value = "com.atguigu.spring5.aopAnnotation.UserProxy.pointDemo()") //使用相同切入点抽取的方法pointDemo()
    public void before() {
    System.out.println("before2…");
    }
    }

    完全注解开发

    @Configuration
    @ComponentScan(basePackages = "com.atguigu.spring5.aopAnnotation")
    @EnableAspectJAutoProxy(proxyTargetClass = true) //默认为false也能执行,为什么?
    public class AOPConfig {
    }

    测试类

    public class TestDemo {

    @Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user", User.class);
        user.add();
    }
    
    @Test
    public void test2() { //完全注解开发
        ApplicationContext context = new AnnotationConfigApplicationContext(AOPConfig.class);
        User user = context.getBean("user", User.class);
        user.add();
    }

    }


    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.atguigu.spring5.aopAnnotation"></context:component-scan>
    
    <!--开启生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>


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

    <!--创建对象-->
    <bean id="book" class="com.atguigu.spring5.aopXML.Book"></bean>
    <bean id="bookProxy" class="com.atguigu.spring5.aopXML.BookProxy"></bean>
    
    <!--配置aop-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopXML.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy" order="1">
            <!--配置增强方法作用在具体方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

04 JdbcTemlate

  • 什么是JdbcTemplate:Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

  • 准备:引入相关jar包

    • spring-tx-5.2.6.RELEASE.jar
      spring-orm-5.2.6.RELEASE.jar
      spring-jdbc-5.2.6.RELEASE.jar
      mysql-connector-java-5.1.7-bin.jar
      druid-1.1.9.jar
    • 配置数据库连接池
    • 配置JdbcTemplate对象,注入dataSource
    • 创建service类,创建dao类,在dao类中注入jdbcTemplate对象


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

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>
    
    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>

    @Service
    public class BookService {
    @Autowired
    private BookDao bookDao;
    }

    public interface BookDao {
    }

    @Repository
    public class BookDaoImp implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    }

  • 创建数据库表对应的实体类

  • 在service中添加add功能,对应的在BookDao接口中添加,在Dao实现类中使用JdbcTemplate的update方法实现具体功能

    @Service
    public class BookService {
    @Autowired
    private BookDao bookDao;

    public void addBook(Book book) {
        bookDao.add(book);
    }

    }

    public interface BookDao {
    void add(Book book);
    }

    @Repository
    public class BookDaoImp implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(Book book) {
        String sql = "insert into book values(?,?,?)";
        Object[] args = {book.getId(), book.getName(), book.getStatus()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    }

    // 实体类
    public class Book {
    private String id;
    private String name;
    private String status;

    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getStatus() {
        return status;
    }
    
    public void setStatus(String status) {
        this.status = status;
    }

    }

    // 测试
    public class TestDemo {
    @Test
    public void testJdbcTemplate () {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    BookService bookService = context.getBean("bookService", BookService.class);
    Book book = new Book();
    book.setId("id1");
    book.setName("name1");
    book.setStatus("status1");
    bookService.addBook(book); //测试添加功能
    }
    }

    //返回值
    Override public int selectCount() {
    String sql = "select count(*) from t_book"; Integer count =
    jdbcTemplate.queryForObject(sql, Integer.class);
    return count;
    }

    //返回对象
    @Override public Book findBookInfo(String id) {
    String sql = "select * from t_book where user_id=?"; //调用方法
    Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper Book.class), id);
    return book;
    }

    //返回集合
    @Override public List findAllBook() {
    String sql = "select * from t_book"; //调用方法
    List bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Book.class));
    return bookList;
    }

    //批量添加
    @Override public void batchAddBook(List batchArgs) {
    String sql = "insert into t_book values(?,?,?)";
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));
    }

    //批量修改
    @Override public void batchUpdateBook(List batchArgs) {
    String sql = "update t_book set username=?,ustatus=? where user_id=?"; int[] ints =
    jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));
    }

    //批量删除
    @Override public void batchDeleteBook(List batchArgs) {
    String sql = "delete from t_book where user_id=?";
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));
    }

05 事务管理

  • 什么是事务:事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败

  • 四个特性(ACID):(1)原子性(2)一致性(3)隔离性(4)持久性

  • 事务添加到JavaEE三层结构里面Service层(业务逻辑层)

  • 两种方式:编程式事务管理声明式事务管理(使用)

  • 声明式事务管理:(1)基于注解方式(使用)(2)基于xml配置文件方式,底层使用AOP原理

  • Spring事务管理API,提供一个接口,代表事务管理器,针对不同的框架提供不同的实现类

  • xml中配置事务管理器,开启事务注解

  • 使用注解@Transactional,可以加在类上面,也可以加在方法上面

  • 其中的参数配置:

    • propagation,有7种,常用的有两种REQUIRED和REQUIRED_NEW,考虑a方面调用b方法,对于前者,如果a有事务,调用b后使用a里面的事务,如果a没有事务,创建新事务;对于后者,不管a有没有事务都创建新事务
    • isolation,事务隔离级别,有4中,对应三个读问题,脏读,不可重复读,幻读
    • timeout,超时时间,规定事务提交时间,未提交则回滚
    • readOnly,是否只读,默认false,可以读可以写
    • rollbackFor,回滚,设置出现哪些异常进行回滚
    • noRollbackFor,不回滚,设置出现那里写异常不回滚


    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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>
    
    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
    
    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

    public interface UserDao {
    void reduceMoney();
    void addMoney();
    }

    @Repository
    public class UserDaoImp implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //Lucy转账100给Mary
    @Override
    public void reduceMoney() {
        String sql = "update account set money = money - ? where name = ?";
        jdbcTemplate.update(sql,100,"lucy");
    }
    
    //Mary收到100
    @Override
    public void addMoney() {
        String sql = "update account set money = money + ? where name = ?";
        jdbcTemplate.update(sql,100,"mary");
    }

    }

    @Service
    @Transactional
    public class UserService {
    @Autowired
    private UserDao userDao;

    public void operation() {
        userDao.reduceMoney();

    // int id = 1/0;
    userDao.addMoney();
    }
    }

  • 配置事务管理器,配置通知,配置切入点和切面,(基于AOP实现的)


    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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db_spring"/>
        <property name="username" value="root"/>
        <property name="password" value="999999"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>
    
    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
    
    <!--1创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--2配置通知-->
    <tx:advice id = "txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则在哪个方法上面添加事务-->
            <tx:method name="operation" propagation="REQUIRED"/>


    <!--3配置切入点和切面-->
    <aop:config>
        <!--配置切入点 需要增强的部分-->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>

  • 创建配置类,使用@Configuration

  • 开启组件扫描,使用@ComponentScan(basePackages = "com.atguigu.spring5")

  • 开启事务管理,使用@EnableTransactionManagement

  • 创建数据库连接池,使用@Bean

  • 创建JdbcTemplate对象,使用@Bean

  • 创建事务管理器,使用@Bean

    @Configuration //配置类
    @ComponentScan(basePackages = "com.atguigu.spring5") //开启组件扫描
    @EnableTransactionManagement //开启事务管理
    public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///user_db_spring");
    dataSource.setUsername("root");
    dataSource.setPassword("999999");
    return dataSource;
    }
    //创建JdbcTemplate对象, 注入dataSource
    @Bean
    public JdbcTemplate getJdbctemplate(DruidDataSource dataSource) {
    //到IOC容器中找dataSource
    JdbcTemplate jdbcTemplate = new JdbcTemplate();
    jdbcTemplate.setDataSource(dataSource); //注入DataSource
    return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource dataSource) {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);
    return transactionManager;
    }
    }

06 Spring5新特性

  • 整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

  • Spring5框架自带了通用的日志封装,移除Log4jConfigListener,官方建议使用Log4j2

    • 引入相关jar包:
      log4j-api-2.11.2.jar
      log4j-core-2.11.2.jar
      log4j-slf4j-impl-2.11.2.jar
      slf4j-api-1.7.30.jar
    • 配置log4j2.xml

  • Spring5框架核心容器支持@Nullable注解,可以使用在方法、属性、参数上面,表示可以为空

  • Spring5核心容器支持函数式风格GenericApplicationContext

    //函数式风格创建对象,交给spring进行管理
    @Test
    public void testGenericApplicationContext() { //1 创建GenericApplicationContext对象
    GenericApplicationContext context = new GenericApplicationContext(); //2 调用context的方法对象注册
    context.refresh();
    context.registerBean("user1",User.class,() -> new User()); //3 获取在spring注册的对象 // User user = (User)context.getBean("com.atguigu.spring5.test.User"); User
    user = (User)context.getBean("user1");
    System.out.println(user);
    }

  • Spring5支持整合JUnit5

    @RunWith(SpringJUnit4ClassRunner.class) //单元测试框架 @ContextConfiguration("classpath:bean1.xml") //加载配置文件
    public class JTest4 {
    @Autowired
    private UserService userService;

    @Test
    public void test1() {
        userService.accountMoney();
    }

    }

    //使用JUnit5
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration("classpath:bean1.xml")
    //@SpringJUnitConfig(locations = "classpath:bean1.xml") //使用复合注解代替上面两个注解
    public class JTest5 {
    @Autowired
    private UserService userService;

    @Test public void test1() {
        userService.accountMoney();
    }

    }

07 Spring5框架新功能(Webflux)

  • 需要基础知识:SpringMVC,SpringBoot,Maven,Java8新特性