Spring5框架

什么是Spring?

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架

什么是IOC?

1、IOC思想是基于IOC容器来完成,IOC容易底层就是对象工程

Spring提供IOC容器实现的两种方式:
    ①: BeanFactory是IOC容器基本实现,是Spring使用的内部接口,不建议开发人员使用
         * 加载配置文件的时候不会创建对象,直到获取对象的时候才会去创建对象

    ②: ApplicationContext接口, BeanFactory的子接口,提供更多强大的功能,供开发人员使用
        * 加载配置文件时就会把配置文件里的对象进行创建

ApplicationContext接口的实现类:
ClassPathXmlApplicationContext与FileSystemXmlApplicationContext实现类的区别
    1、ClassPathXmlApplicationContext类是以当前的src下的路径查找配置文件
    2、FileSystemXmlApplicationContext类是以计算机的磁盘下的路径查找配置文件

小结: 开发时一般我们都使用ApplicationContext类,因为我们希望在程序运行时就把一些需要使用的对象都创建好

1、IOC操作Bean管理 - 基于xml配置

①、在Spring的xml配置中,使用bean标签来对类进行配置,其中bean标签内常用的属性有:

  • id属性: 唯一标识,相当于给类创建别名
  • class属性: 提供对象的全类名(相当于类的地址)
  • name属性: 与id属性相同,唯一不同的是他可以添加特殊符号

通过bean标签创建对象

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

②、IOC基于xml创建对象时使用的是无参构成器,假设类中只有带参构造器而没无参构造器,创建过程中会报错

2、IOC基于xml方式注入属性

DI: 依赖注入、注入属性,(dependency injection)依赖注入基于对象的创建方式实现
第一种注入的方式: 使用set方法进行注入

2.1、创建对象,定义属性和对应的set方法

package com.atguigu.bean;

/**
 * @author gdcho
 * @create 09-26-20:15
 */
public class Book {
    private Integer id;
    private String bookName;
    private String author;

    public Book(Integer id, String bookName, String author) {
        this.id = id;
        this.bookName = bookName;
        this.author = author;
    }

    public Book() {}

    public Integer getId() {return id;}

    public void setId(Integer id) {this.id = id;}

    public String getBookName() {return bookName;}

    public void setBookName(String bookName) {this.bookName = bookName;}

    public String getAuthor() {return author;}

    public void setAuthor(String author) {this.author = author;}
}

2.2、在spring的xml配置中,配置bean标签配置创建对象,再在bean标签内部配置property注入属性

    <!--1.配置Book的对象创建-->
    <bean id="book" class="com.atguigu.bean.Book" >
        <!--2.配置属性注入-->
        <property name="id" value="5"></property>
    </bean>

2.3、使用p名称空间可以简化xml配置属性注入的方式
    ①、添加p名称空间在xml配置文件中
xmlns:p="http://www.springframework.org/schema/p"
在这里插入图片描述
    ②、进行属性注入,在bean标签里面进行操作

    <!--1.配置Book的对象创建-->
    <bean id="book" class="com.atguigu.bean.Book">
        <!--2.配置属性注入-->
        <property name="id" value="5"></property>
    </bean>

    ③、第二总注入方式: 使用有参构造器进行注入

    <!--1.配置Book的对象创建-->
    <bean id="book" class="com.atguigu.bean.Book">
        <!--配置有参构造器注入属性-->
        <constructor-arg name="author" value="gghhy66"></constructor-arg>
    </bean>

2.4、在spring中的xml配置属性注入null值、特殊符号的值
    ①、属性中注入null值的方式,在property标签内创建null标签

        <!--实现注入属性值null-->
        <bean id="book2" class="com.atguigu.bean.Book">
            <property name="bookName">
               <null></null>
            </property>
        </bean>

    ②、属性中注入特殊字符
           注入方式1: 把特殊符号转义

        <bean id="book3" class="com.atguigu.bean.Book">
            <property name="bookName" value="&lt;&lt;活着&gt;&gt;"></property>
        </bean>

           注入方式2: 把带特殊符号内容写到 <![CDATA[内容]]>

        <bean id="book4" class="com.atguigu.bean.Book">
            <property name="bookName" >
                <value><![CDATA[<<活着>>]]></value>
            </property>
        </bean>
3、使用xml配置注入bean对象

3.1、首先使用spring中xml配置创建对象,与被注入的对象
3.2、在要注入属性的bean标签内创建property标签,内部使用ref属性引入被创建对象的别名

方式1: 在property标签内使用ref属性引入被创建对象的id

    <!--创建要注入属性的对象-->
    <bean id="userService" class="com.atguigu.service.UserService">
        <!--ref属性注入Bean对象类型的id值-->
        <property name="userDao" ref="userDao"></property>
    </bean>
    <!--被注入Bean对象类型的创建-->
    <bean id="userDao" class="com.atguigu.dao.UserDaoImpl"></bean>

方式2: 使用xml配置文件注入属性 - 级联赋值

  • 在xml配置文件内使用bean标签创建对象
  • 在bean标签中创建property标签注入属性
  • 在需要使用bean对象的属性内property标签内创建新的对象
    <bean id="emp" class="com.atguigu.bean.Employee">
        <!--在属性注入内部创建需要注入的Bean对象-->
        <property name="manager">
            <bean id="manger" class="com.atguigu.bean.Manager"></bean>
        </property>
    </bean>

小结: ref属性: 是property标签内的注入bean对象的属性

4、使用xml配置注入属性 - 注入集合类型

4.1、在xml配置中使用bean标签创建对象
4.2、在bean标签内使用property标签,name属性获取属性名
4.3、property内部使用各个集合的标签并且使用value标签添加元素

    <bean id="stu" class="com.atguigu.collection.Stu">
        <!--数组类型属性注入-->
        <property name="courses">
            <array>
                <value>123</value>
                <value>我是谁</value>
            </array>
        </property>

        <!--list类型属性注入-->
        <property name="list">
            <list>
                <value>小明</value>
                <value>大明</value>
            </list>
        </property>

        <!--map类型属性注入-->
        <property name="maps">
            <map>
                <entry key="key1" value="value1"></entry>
                <entry key="key2" value="value2"></entry>
            </map>
        </property>

        <!--set类型属性注入-->
        <property name="sets">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
    </bean>

4.4、集合类型属性注入 - 集合里的值为对象类型

	<bean>
        <!--list类型属性注入, 值为对象类型-->
        <property name="listCourse">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
    </bean>
	<!--创建要注入的list的元素对象-->
    <bean id="course1" class="com.atguigu.collection.Course">
        <property name="course" value="Java"></property>
    </bean>
    <bean id="course2" class="com.atguigu.collection.Course">
        <property name="course" value="MyBatis"></property>
    </bean>

4.5、集合类型属性注入 - 把集合提取出来成为公共的标签
①、xml配置文件中引入util命名空间

在这里插入图片描述

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

②、使用<util:list id="list">将集合类型抽取为公共的标签

<bean id="stu" class="com.atguigu.collection.Stu">
        <!--属性注入这里引用公共的集合id-->
        <property name="list" ref="list"></property>
    </bean>
    
    <!--将list抽取为公共的标签-->
    <util:list id="list">
        <value>123</value>
        <value>abc456</value>
    </util:list>

5、操作Bean管理 - FactoryBean工厂bean

Spring有两种Bean类,一种是普通Bean类,另一种是工厂Bean
    1、普通Bean: 在配置文件中的类型就是返回值类型
    2、工厂Bean: 在配置文件中的类型可以和返回值类型不一样

工厂Bean的创建方式:
    ①、创建工厂bean对象,实现接口FactoryBean泛型为指定为要创建的bean对象
    ②、实现接口里面的方法,在方法里面定义返回值类型

//泛型决定了要返回的对象
public class MyBean implements FactoryBean<Book> {

    @Override
    public Book getObject() throws Exception {
        Book book = new Book(10,"活着","余华");
        return book;
    }
}

    ③、在配置文件中配置创建FactoryBean的类

    <bean id="myBean" class="com.atguigu.bean.MyBean">

6、 在Spring中设置创建bean实例是单实例还是多实例

6.1、默认情况下,bean创建后为单实例
    验证: 通过相同的配置文件创建两个Bean对象,输出后地址为相同值

6.2、如何在spring中配置文件中创建对象是单例还是多例
    答: bean标签中有个属性scope,它有两个常用的值singleton设置单例(默认),prototype设置多例
在这里插入图片描述

singleton与prototype的区别
    1)、single为单实例、prototype为多实例
    2)、xml配置创建bean对象默认是单实例,而Bean对象随着配置的加载而创建
    3)、xml配置创建bean对象设置scope属性为prototype时,它不会随着配置文件的加载而创建,而是在调用getBean方法时候创建


7、通过IOC创建的bean对象生命周期

①、通过构造器创建bean实例
②、调用初始化方法, 需要配置xml文件的bean标签
③、为bean属性设置值和对其它bean进行引用
④、获取到实例对象可以使用
⑤、容器关闭后,手动销毁容器, 需要配置xml文件的bean标签

第2、5步需要配置标签
在这里插入图片描述
配置文件

    <bean id="person" class="com.atguigu.bean.Person" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="Roy"></property>
        <property name="age" value="88"></property>
    </bean>

bean对象完成,手动销毁ioc容器

    @Test
    public void testBean2(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
        Person person = context.getBean("person", Person.class);
        System.out.println("第四步 实例化bean对象成功");

        //手动销毁容器
        context.close();
    }

测试结果
在这里插入图片描述

8、操作Bean管理 - 完全基于注解bean对象创建

8.1、什么是注解?
    1、注解是代码的特殊标记, 格式: @注解名(属性名=属性值,属性名=属性值,…)
    2、注解可以使用在的地方: 类上、方法名上、属性上
    3、使用注解的目的: 简化spring的xml配置

8.2、Spring针对Bean管理创建对象提供的注解
    @Component 使用在视图层
    @Service 使用在业务层
    @Controller 使用在控制层
    @Repository 使用在持久层
* 上面4个注解的功能是一样的,都可以用来创建Bean对象,在不同的层中用不同的注解以区分

8.3、通过注解的方式创建Bean对象的步骤
    1、引入需要依赖的包
          aop、beans、context、core、expression、logging这些jar包
在这里插入图片描述

    2、创建xml配置文件,引入名称空间: context、开启组件扫描:<context:component-scan base-package="com.atguigu">
         组件扫描如果要扫描多个包,用逗号相隔

	<!--base-package属性: 扫描包下所有有创建bean对象的注解-->
    <context:component-scan base-package="com.atguigu.dao"></context:component-scan>

    3、创建类,并在类名上方添加Bean管理的注解
         类上添加的注解可以不用写,默认类名称是把类名首字母小写
在这里插入图片描述

8.4、IOC操作Bean管理 - 基于注解方式实现属性注入
1、@Autowired 根据属性类型自动注入,添加到需要实现注入的属性名上
2、@Qualifier 与@Autowired注解搭配使用,如果自动注入类型对象有多个,@Qualifier注解选定其中一个
3、@Resource 可以根据属性类型注入,可以根据名称注入
4、@Value 能够注入普通类型属性

//创建bean对象的注解
@Service
public class UserService {
    //根据类型注入属性
    @Autowired
    private UserDao userDao;

    //根据类型与类名注入属性
    @Autowired
    @Qualifier("userDaoImpl")
    private UserDao userDao;

    //根据类型注入属性
    @Resource
    private UserDao userDao1;

    //根据类名注入属性
    @Resource(name="userDaoImpl2")
    private UserDao userDao2;
    
    //注入普通类型
    @Value("Monica")
    private String username;
}
8.5 IOC操作Bean管理 - 完全基于注解的Spring开发

1、创建一个类,作为配置类
2、在类名上添加@Configuration注解
3、在类名上添加@ComponentScan注解,扫描哪些包要创建对象

@Configuration
@ComponentScan(basePackages = {"com.atguigu.dao","com.atguigu.service"})
public class SpringConfig {

}

4、创建普通类,并在类名上添加创建对象的注解属性注入注解

@Component("human")
public class Human {
    @Value("Roy")
    private String name;
    
    @Value("22")
    private Integer age;
    
    @Value("180")
    private Integer height;

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

    public void setAge(Integer age){this.age = age;}

    public void setHeight(Integer height) {this.height = height;}
    
    public void getInfo(){
        System.out.println("name = " + name + ", age = " + age + ", height = " + height);
    }
}

5、测试完全通过注解创建bean

    @Test
    public void test3(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Human human = context.getBean("human", Human.class);
        human.getInfo();
    }

在这里插入图片描述


AOP是什么?

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

1、AOP操作 - 准备工作

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

    (2)基于AspectJ实现AOP操作的两种实现
        ①、基于xml配置的方式实现
        ②、基于注解方式实现

    (3)在项目中导入AOP相关依赖
在这里插入图片描述

    (4)切入点表达式: 知道对那个方法进行增强操作
         切入点表达式格式: execution([权限修饰符][返回值类型][全类名][方法名](参数列表))

1.2、 AOP的术语
    1、连接点: 类中实际可以增强的方法称为连接点
    2、切入点: 类中实际被增强的方法称为切入点
    3、通知(增强):
        ①、实际增强的逻辑部分称为通知
        ②、通知的种类: 前置通知、后置通知、环绕通知、异常通知、最终通知
    4、切面: 把通知应用到切入点的过程

以下是五种通知的注解使用

@Repository  //创建对象的注解
@Aspect  //设置代理对象的注释
public class UserProxy {

    //创建一个方法,方法上添加公共的切入点注解,作为增强方法上放的注解
    @Pointcut("execution(* com.atguigu.service.User.add(..))")
    public void pointdemo(){

    }

    //在增强类里面,作为通知方法上面添加通知类型注解,使用切入点表达式进行配置
    //前置通知
    @Before("pointdemo()")
    public void before(){
        System.out.println("before......");
    }

    //前置通知
    @AfterReturning("pointdemo()")
    public void afterReturning(){
        System.out.println("before......");
    }


    //最终通知
    @After("pointdemo()")
    public void after(){
        System.out.println("after......");
    }

    //环绕通知
    @Around("pointdemo()")
    public void surround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Surround......Surround");
        proceedingJoinPoint.proceed();
        System.out.println("SurroundAfter......SurroundAfter");
    }

    //异常通知
    @AfterThrowing("pointdemo()")
    public void exception(){
        System.out.println("AfterThrowing......");
    }
}

2、AOP操作 - 基于xml配置的方式实现

    1、创建类,在类里面添加方法

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

    2、创建增强类

public class HumanProxy {
}

    3、在spring配置,引入aop名称空间,开启增强方法查找
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns: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/aop/spring-aop.xsd">
    <!--被增强类的创建对象-->
    <bean id="human" class="com.atguigu.service.Human"></bean>

    <!--这增强类的创建对象-->
    <bean id="humanProxy" class="com.atguigu.service.HumanProxy"></bean>

    <aop:config>
        <!--aop:pointcut标签配置切面动作-->
        <aop:pointcut id="p" expression="execution(* com.atguigu.service.Human.add(..)))"/>
        <aop:aspect ref="humanProxy">
            <!--aop:before标签配置: 前置通知-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
            <!--aop:after-returning标签配置: 后置通知-->
            <aop:after-returning method="afterReturning" pointcut-ref="p"></aop:after-returning>
        </aop:aspect>
    </aop:config>
</beans>

    4、在增强类里面编写增强逻辑,创建不同类型的通知方法

public class HumanProxy {

    //前置通知
    public void before(){
        System.out.println("before......");
    }

    //后置通知
    public void afterReturning(){
        System.out.println("afterReturning......");
    }
}

5、测试要增强的方法

    @Test
    public void test3(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beantest.xml");
        Human human = context.getBean("human", Human.class);
        human.add();
    }

结果
在这里插入图片描述

AOP操作的两个注意点:
        ①、如果通知方法上方的切入点注解表达式使用相同,可以将切入点表达式抽取出来创建一个方法,在方法上方添加切入点注解,作为增强方法上放的注解
        ②、有多个相同的增强方法增强同一个方法时,在增强方法上添加@Order(数值类型值)注解,值越小优先级越高


3、AOP操作 - 基于注解方式实现

    1、创建一个类,在类上方使用@Configuration注解用于作为配置类
    2、在配置类上添加@Component注解用于扫描匹配的注解创建对象@EnableAspectJAutoProxy通过扫描注解匹配增强方法

@Configuration  //基于注解配置spring
@ComponentScan(basePackages = {"com.atguigu"})  //通过注解扫描匹配的注解创建对象
@EnableAspectJAutoProxy(proxyTargetClass = true)  //通过扫描注解匹配增强方法
public class SpringConfig {
}

    3、创建普通类添加创建对象注释,在类中创建被增强方法

@Repository  //创建对象的注解
public class Dog {
    public void wow(){
        System.out.println("wow......");
    }
}

    4、创建增强类,在类上添加匹配增强类的注解、创建对象注释

@Aspect  //注解代理类
@Repository
public class DogProxy {

    //抽取切入点,创建为公共的切入点
    @Pointcut("execution(* com.atguigu.config.Dog.wow(..))")
    public void pointCut(){
    }
	
	//前置通知
    @Before("pointCut()")
    public void sleep(){
        System.out.println("sleep......");
    }
	
	//后再通知
    @AfterReturning("pointCut()")
    public void eat(){
        System.out.println("eat bone......");
    }
}

    5、测试被增强方法的调用

    @Test
    public void test2(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Dog dog = context.getBean("dog", Dog.class);
        dog.wow();
    }

    结果
在这里插入图片描述

JdbcTemplate是什么?

JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。

1、使用JdbcTemplate

1、在工程中引入所需的jar包,这里需要使用JdbcTemplate、IOC、Mysql等jar包
在这里插入图片描述
2、准备一个数据库,User数据表中有准备些数据
在这里插入图片描述
3、创建xml配置文件,里面添加bean标签引入dataSource

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

	<!--加载mysql数据库-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url">
            <value><![CDATA[jdbc:mysql://localhost:3306/book_review?useUnicode=true&characterEncoding=utf-8]]></value>
        </property>

        <property name="username" value="root" />
        <property name="password" value="1234" />
        <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"></context:component-scan>
</beans>

4、创建持久层dao,创建UserDao接口

@Repository
public interface UserDao {

    /**
     * 添加用户
     *
     * @param user 用户
     */
    void addUser(User user);

    /**
     * 更新用户
     *
     * @param user 用户
     */
    void updateUser(User user);

    /**
     * 删除用户的id
     *
     * @param id id
     */
    void deleteUserById(int id);


    /**
     * 批量添加用户
     *
     * @param listUser 用户列表
     */
    void batchAddUser(List<Object[]> listUser);


    /**
     * 查询用户的id
     *
     * @param id id
     * @return {@link User}
     */
    User queryUserById(int id);

    List<User> queryAllUser();
}

5、创建UserDao的实现类

@Repository  //创建对象的注解
public class UserDaoImpl implements UserDao {

    @Autowired  //自动转配属性
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addUser(User user) {
        String sql = "insert into b_user(`id`,`username`,`password`,`email`) values(?,?,?,?)";
        //调用jdbcTemplate类封装好的update方法进行增、删、改
        jdbcTemplate.update(sql,user.getId(),user.getUsername(),user.getPassword(),user.getEmail());
    }

    @Override
    public void updateUser(User user) {
        String sql = "update b_user set `username`=?,`password`=?,`email`=? where id=?";
        jdbcTemplate.update(sql,user.getUsername(),user.getPassword(),user.getEmail(),user.getId());
    }

    @Override
    public void deleteUserById(int id) {
        String sql = "delete from b_user where id=?";
        jdbcTemplate.update(sql,id);
    }

    @Override
    public void batchAddUser(List<Object[]> listUser) {
        String sql = "insert into b_user(`id`,`username`,`password`,`email`) values(?,?,?,?)";
        jdbcTemplate.batchUpdate(sql,listUser);
    }

    @Override
    public User queryUserById(int id) {
        String sql = "select `id`,`username`,`password`,`email` from b_user where id=?";
        //调用jdbcTemplate类封装好的query方法进行查询
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class),id);
    }

    @Override
    public List<User> queryAllUser() {
        String sql = "select `id`,`username`,`password`,`email` from b_user";
        return jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class));
    }
}

6、创建服务层Service

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void addUser(User user){
        userDao.addUser(user);
    }

    public void updateUser(User user){
        userDao.updateUser(user);
    }

    public void deleteUserById(int id){
        userDao.deleteUserById(id);
    }

    public void batchAddUser(List<Object[]> listUser){
        userDao.batchAddUser(listUser);
    }

    public User queryUserById(int id){
        return userDao.queryUserById(id);
    }

    public List<User> queryAllUser(){
        return userDao.queryAllUser();
    }
}

7、测试类

public class UserServiceTest {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    UserService userService = context.getBean("userService", UserService.class);
    @Test
    public void addUser() {
        userService.addUser(new User(null,"abc678","123456abc","abc678@qq.com"));
    }

    @Test
    public void updateUser(){
        userService.updateUser(new User(1,"channel123","channel123","channel@qq.com"));
    }

    @Test
    public void deleteUserById(){
        userService.deleteUserById(10);
    }

    @Test
    public void batchAddUser(){
        List<Object[]> list = new ArrayList<>();
        Object[] o1 = {null,"Morty","morty123","morty@qq.com"};
        Object[] o2 = {null,"Monica","monica123","monica@qq.com"};
        list.add(o1);
        list.add(o2);
        userService.batchAddUser(list);
    }

    @Test
    public void queryUserById(){
        System.out.println(userService.queryUserById(1));
    }

    @Test
    public void queryAllUser(){
        userService.queryAllUser().forEach(System.out::println);
    }
}

Jdbctemplate中的事物操作管理

1、什么是事物?

事物是数据库操作的最基本单元,逻辑上一组操作,要么都成功,如果有一个失败则都失败

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

在Spring进行事物管理操作
有两种处理事物的方式: 编程式事物管理、声明式事物管理(注解与配置文件)

在开发中,我们都使用声明式事物管理的方式,因为编程式事物管理过于麻烦,不利于维护

声明式事物管理的两种方式
1、基于配置文件的事物管理
2、基于注解的事物管理

Spring提供的事物管理API
PlatformTransactionManager接口,代表事物管理器,针对不同的框架提供不同的实现类
在这里插入图片描述

2、搭建事物操作环境

在开发过程中我们service、dao层都可以用于添加事物管理,但一般在service添加事物管理更有利于我们后期维护
在这里插入图片描述
2.1、引入工程需要的jar包
在这里插入图片描述
2.2、需要有个Account账户数据表,添加两条数据
在这里插入图片描述
2.3、创建配置文件,引入名称空间
context命名空间: 用于扫描要创建bean对象的注解
aop命名空间: 用于实现动态代理
tx命名空间: 开启事物管理器,tx的底层使用的是aop动态代理在对数据库操作的方法插入前置后置通知

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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/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">
    <!--开启组件扫描: 扫描有创建对象的注解-->
    <context:component-scan base-package="com.atguigu"></context:component-scan>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url">
            <value><![CDATA[jdbc:mysql://localhost:3306/book_review?useUnicode=true&characterEncoding=utf-8]]></value>
        </property>

        <property name="username" value="root" />
        <property name="password" value="1234" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>

    <!--jdbcTemplate注入dataSource-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--创建事物管理器-->
    <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>
</beans>

2.4、创建service、搭建dao、完成对象创建和注入关系
service注入dao、dao注入JdbcTemplate、JdbcTemplate注入DataSource

AccountDao类

@Repository
public interface AccountDao {

    /**
     * 减少钱
     *
     * @param id    id
     * @param money 钱
     */
    void reduceMoney(int id,int money);

    /**
     * 添加钱
     *
     * @param id    id
     * @param money 钱
     */
    void addMoney(int id,int money);
}

AccountDao实现类,注入JdbcTemplate属性

@Repository
public class AccountDaoImpl implements AccountDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void reduceMoney(int id, int money) {
        String sql = "update b_account set `balance`=`balance`-? where id=?";
        jdbcTemplate.update(sql,money,id);
    }

    @Override
    public void addMoney(int id, int money) {
        String sql = "update b_account set `balance`=`balance`+? where id=?";
        jdbcTemplate.update(sql,money,id);
    }
}

在service 类上面(或者 service 类里面方法上面)添加事务注解
(1)@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务

@Service
@Transactional  //添加事物管理的注释
public class AccountService {

    @Autowired  //注入AccountDao对象
    private AccountDao accountDao;

    public void transfer(int id,int toId,int money){
        //A账户减少金额
        accountDao.reduceMoney(id,money);

        //B账户增加金额
        accountDao.addMoney(toId,money);

    }
}

2.5 测试方法

public class AccountServiceTest {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    @Test
    public void transfer() {
        AccountService accountService = context.getBean("accountService", AccountService.class);
        //1号转账给2号500
        accountService.transfer(1,2,500);
    }
}

在对数据库修改过程中无异常,成功结果
在这里插入图片描述
往service层添加异常测试

@Service
@Transactional  //添加事物管理的注释
public class AccountService {

    @Autowired  //注入AccountDao对象
    private AccountDao accountDao;

    public void transfer(int id,int toId,int money){
        //A账户减少金额
        accountDao.reduceMoney(id,money);

        //在两个事物传播之间插入一条异常
        int i = 10/0;

        //B账户增加金额
        accountDao.addMoney(toId,money);

    }
}

测试增加异常后的结果
在这里插入图片描述


3、事物管理操作 - 声明式事物管理参数配置

3.1、在service中添加@Transactional事物管理注解,它有几个参数可以用于配置事物相关数据

以下几个重要的参数划出来
在这里插入图片描述
(1)、propogation() : 事物传播行为
多个事物方法进行调用,这个过程如何进行管理的

Spring框架事物传播行为有7种,其中这两种比较常用
在这里插入图片描述
在这里插入图片描述
(2)、isolation(): 事物隔离级别

    1、事物与事物之间的特性称为隔离性, 多个事物操作不会产生影响, 不考虑隔离层的事物会产生很多问题
    2、有三个读的问题: 脏堵、不可重复读、幻读
          脏读:一个未提交事务读取到另一个未提交事务的数据
          不可重复读:一个未提交事务读取到另一提交事务修改数据
          虚读:一个未提交事务读取到另一提交事务添加数据
    3、解决:通过设置事务隔离级别,解决读问题
在这里插入图片描述

(3)、timeout:超时时间
    1、事务需要在一定时间内进行提交,如果不提交进行回滚
    2、默认值是 -1 ,设置时间以秒单位进行计算

(4)、readOnly:是否只读
    1、读:查询操作,写:添加修改删除操作
    2、readOnly 默认值 false,表示可以查询,可以添加修改删除操作
    3、设置 readOnly 值是 true,设置成 true 之后,只能查询

(5)、rollbackFor:回滚
    设置出现哪些异常进行事务回滚

(6)、noRollbackFor:不回滚
    设置出现哪些异常不进行事务回滚

4、事物操作 - xml配置声明式事物管理

这里创建对象、连接数据库、事物管理全都使用xml配置文件实现

<!--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="accountMoney" propagation="REQUIRED"/>
 <!--<tx:method name="account*"/>-->
 </tx:attributes>
</tx:advice>
<!--3 配置切入点和切面-->
<aop:config>
 <!--配置切入点-->
 <aop:pointcut id="pt" expression="execution(* 
com.atguigu.spring5.service.UserService.*(..))"/>
 <!--配置切面-->
 <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
5、事物操作 - 完全注解声明式事物管理

1、创建配置类,替代xml配置文件

@Configuration  //设置为配置类
@ComponentScan(basePackages = {"com.atguigu"})  //开启对象扫描
@EnableTransactionManagement  //开启事物管理
public class SpringConfig {

    @Bean  //Bean注解是创建的这个对象注册到IOC容器中
    public DruidDataSource getDruidDataSource(){
        //创建一个DruidDataSource();
        DruidDataSource dataSource = new DruidDataSource();

        //获取到配置信息
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("1234");
        dataSource.setUrl("jdbc:mysql://localhost:3306/book_review?useUnicode=true&characterEncoding=utf-8");
        return dataSource;
    }

    @Bean  //Bean注解也可以根据参数列表的类型获取IOC容器中的对象
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //创建JdbcTemplate对象获取数据源
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean  //将DataSourceTransactionManager类型的对象注册到IOC容器中
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        //获取事物管理的数据库
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

2、测试方法

    @Test
    public void transfer2() {
        //使用AnnotationConfigApplicationContext(SpringConfig.class)获取到IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService accountService = context.getBean("accountService", AccountService.class);
        //1号转账给2号500
        accountService.transfer(1,2,500);
    }

Spring5框架的新功能

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

1、Spring5自带了通用的日志封装
(1)、Spring移出了Log5jConfigLisenter,采用了Log4j2
(2)、Spring5框架整合了Log4j

第一步: 引入jar包
在这里插入图片描述
第二步: 创建log4j2.xml配置文件(配置文件名只能是这个)
并且配置文件的内容都是固定的

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

运行后控制台就会输出日志内容
在这里插入图片描述


2、Spring框架核心容器支持@Nullable注解

@Nullable可以使用在方法上、属性上、参数上, 表示方法返回值可以为空、属性值可以为空、参数可以为空

①、注解用在方法上面,方法返回值可以为空
在这里插入图片描述
②、注解使用在属性上面,表示属性值可以为空
在这里插入图片描述
③、注解使用在方法参数里面,方法参数可以为空
在这里插入图片描述


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

首先函数式风格是Java8引入的lambda表达式编程,可以以更加简洁的方式编写代码
所以Spring5框架支持函数式编程能够更加高效的编写代码

    @Test
    ///函数式风格创建对象,交给 spring 进行管理
    public void testGenericApplicationContext(){
        //1、创建GenericApplicationContext对象
        GenericApplicationContext context = new GenericApplicationContext();
        //2.调用context方法注册IOC容器
        context.refresh();
        context.registerBean("user", User.class,() -> new User());
        //3.获取spring注册的对象
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值