Spring学习?这一篇文章就够,史上最全!

news2024/12/25 14:34:57

文章目录

  • 前言
  • 一、IOC概述及底层原理
    • 1.概述和原理
  • 二、思路分析
  • 三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)
    • 1.xml实现bean管理
      • (1)创建对象
      • (2)注入属性
      • (3)p名称空间注入
      • (4)其他注入
        • 1.注入的属性值是null或者有符号,如下:
        • 2.注入外部bean,如下:
        • 3.内部bean注入
        • 4.级联赋值
        • 5.注入集合
      • (5)FactoryBean(工厂bean)
    • 2.bean的作用域
    • 3.bean的生命周期
    • 4.xml自动配置属性值
    • 5.外部属性文件操作bean
  • 四、注解实现bean管理
    • 1.基于注解创建对象
    • 2.组件扫描细节
    • 3.基于注解进行属性注入
  • 五、完全注解开发
  • 六、AOP概述和原理
    • 1.概述和原理
    • 2.JDK动态代理实例
  • 七、基于AspectJ实现的AOP操作
    • 1.什么是AspectJ
    • 2.AOP相关术语
    • 3.切点表达式
    • 3.基于注解方式实现
      • (1)实例:
      • (2)切入点提取
      • (3)设置增强类优先级
      • (4)完全注解开发
    • 4.基于xml配置文件实现(了解)
  • 八、JdbcTemplate
    • 1.相关依赖(AOP、IOC、JdbcTemplate都有)
    • 2.代码实战
      • (1)方法讲解
      • (2)代码实例
  • 九、事务及其参数含义
    • 1.事务的四个特性
    • 2.事务的传播行为(propagation)
    • 3.事务隔离性
    • 4.事务的隔离级别(ioslation)
    • 5.timeout(超时)
    • 6.readOnly(是否只读)
    • 7.rollbackFor(回滚)
    • 8.noRollbackFor(不回滚)
  • 十、事务管理
    • 1.事务管理的两种形式
    • 2.注解实现声明式事务管理
    • 3.xml实现声明式事务管理
    • 4.完全注解开发
  • 总结


前言

Spring框架:IOC、AOP、JdbcTemplate、事务管理,带你一篇速通。


一、IOC概述及底层原理

1.概述和原理

  • IOC是控制反转的意思。使用对象时候由主动new对象转换成由外部提供对象,此过程中对象的创建权由程序转移到外部,这种思想叫做控制反转。即把对象创建和对象的调用过程交给spring进行管理。
  • 目的:降低耦合度。
  • 底层原理:xml配置,反射,工厂模式。
  • Spring提供IOC容器两种实现方式(两个接口)
    (1)BeanFactory:Spring内部使用的接口,不提倡开发人员使用。特点:加载配置文件时不会创建对象,获取对象时才会创建对象。
    (2)ApplicationContext:BeanFactory的子接口,提供了更多更强大的功能,一般由开发人员使用。特点:加载配置文件时会把配置文件里的对象进行创建。
    (3)核心:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
    IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。
  • ApplicationContext两个常用的实现类:
    (1)FileSystemXmlApplicationContext:绝对路径,从盘符开始算起
    (2)ClassPathXmlApplicationContext:相对路径,从项目的src开始算起
    在这里插入图片描述
  • IOC实现:依赖注入,即在容器中建立bean与bean之间的依赖关系的整个过程。

二、思路分析

  • IOC管理什么(bean对象)
  • 如何告知IOC去管理bean对象(通过配置文件)
  • 被管理的对象交给IOC容器,如何获取IOC容器?(接口)
  • IOC容器得到后,如何获取bean?(通过ApplicationContext接口的两个实现类的getBean方法获取bean实例创建对象)

三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)

首先告诉大家本篇文章的所有使用的spring依赖版本:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.9</version>
        </dependency>
    </dependencies>

1.xml实现bean管理

(1)创建对象

项目的resource资源文件夹创建spring的配置文件,然后添加如下代码:

<bean id="book" class="com.dragon.spring5.Book"></bean>
  • id:创建对象的名称
  • class:Book类的路径
  • 创建对象时默认是执行无参构造函数
    在这里插入图片描述

(2)注入属性

创建对象后,对象内的属性还没有赋值等等,讲诉三种注入属性得到方式:

  • 第一种:set方法注入
    这种方法需要类的属性有对应的set方法,如下:
public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
    public void testbook(){
        System.out.println(bname+":"+bauthor);
    }
}

然后在spring配置文件中通过property标签进行属性注入,如下:

<bean id="book" class="com.dragon.spring5.Book">
			<property name="bname" value="易筋经"></property>
            <property name="bauthor" value="达摩老祖"></property>
</bean>

然后测试:

	<!--加载spring配置文件创建对象-->
	ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
	<!--反射-->
	Book book=context.getBean("book", Book.class);
	System.out.println(book);
	book.testbook();

在这里插入图片描述

  • 第二种:有参构造方法注入
    提供有参构造方法:
public class Book {
    private String bname;
    private String bauthor;

    public Book(String bname, String bauthor) {
        this.bname = bname;
        this.bauthor = bauthor;
    }
    public void testbook(){
        System.out.println(bname+":"+bauthor);
    }
}

然后在spring配置文件中,如下:

<bean id="book" class="com.dragon.spring5.Book">
          <constructor-arg name="bname" value="易筋经"></constructor-arg>
          <constructor-arg name="bauthor" value="达摩老祖"></constructor-arg>
</bean>

(3)p名称空间注入

set方法、测试的代码跟上诉一样,不再赘诉。
在spring配置文件中添加p名称空间,和配置代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       <!--添加p名称空间-->
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
       
		<bean id="book" class="com.dragon.spring5.Book" p:bname="九阴神功" p:bauthor="无名氏"></bean></beans>

在这里插入图片描述

(4)其他注入

1.注入的属性值是null或者有符号,如下:

        <bean id="book" class="com.dragon.spring5.Book">
                <property name="bauthor">
                        <null/>
                </property>
                <property name="bname">
                        <value><![CDATA[<<读者>>]]></value>
                </property>
        </bean>
  • 有符号:用<![CDATA[带符号的属性值(包括符号)]]>
  • 空值:< null />

在这里插入图片描述

2.注入外部bean,如下:

spring配置文件:

  • ref:引用外部bean的id值
    <bean id="userService" class="com.dragon.spring5.service.UserService">
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>

    <bean id="userDaoImpl" class="com.dragon.spring5.dao.UserDaoImpl"></bean>

UserService、UserDao、UserDaoImpl、测试类代码:

package com.dragon.spring5.dao;

public interface UserDao {
    public void update();
}
=============================================================
package com.dragon.spring5.dao;

public class UserDaoImpl implements UserDao{

    @Override
    public void update() {
        System.out.println("dao update.......");
    }
}
=========================================================
package com.dragon.spring5.service;

import com.dragon.spring5.dao.UserDao;

public class UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add........");
        userDao.update();
    }
}
======================================================
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService=context.getBean("userService", UserService.class);
userService.add();

在这里插入图片描述

3.内部bean注入

不通过ref属性,而是通过嵌套一个bean标签实现
spring配置文件:

        <bean id="emp" class="com.dragon.spring5.bean.Emp">
            <property name="enanme" value="lucy"></property>
            <property name="gender" value="女"></property>
            <property name="dept">
                <bean id="dept" class="com.dragon.spring5.bean.Dept">
                    <property name="dname" value="保安部门"></property>
                </bean>
            </property>
        </bean>

Emp、Dept、测试类代码:

package com.dragon.spring5.bean;

public class Emp {
    private String enanme;
    private String gender;
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEnanme(String enanme) {
        this.enanme = enanme;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    public void add(){
        System.out.println(enanme+"::"+gender+"::"+dept);
    }
}
===================================================================
package com.dragon.spring5.bean;

public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dname='" + dname + '\'' +
                '}';
    }
}
==========================================================================
ApplicationContext context1=new ClassPathXmlApplicationContext("bean2.xml");
        Emp emp=context1.getBean("emp", Emp.class);
        emp.add();

在这里插入图片描述

4.级联赋值

写法一:也就是上面所说的外部bean,通过ref属性来获取外部bean
写法二:
emp类中有ename和dept两个属性,其中dept有dname属性,写法二需要emp提供dept属性的get方法。

                <bean id="emp" class="com.dragon.spring5.bean.Emp">
                    <property name="enanme" value="john"></property>
                    <property name="gender" value="男"></property>
                    <!--写法一-->
                    <property name="dept" ref="dept"></property>
                    <!--写法二-->
                    <property name="dept.dname" value="技术部"></property>
                </bean>
                <bean id="dept" class="com.dragon.spring5.bean.Dept">
                    <property name="dname" value="财务部"></property>
                </bean>
5.注入集合

stu类:

package com.dragon.spring5.collectiontype;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Stu {
    private String[] courses;
    private List<String> list;
    private Map<String,String> maps;
    private Set<String> sets;
    private List<Course> courselist;

    public void setCourselist(List<Course> courselist) {
        this.courselist = courselist;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
    public void test(){
        System.out.println(Arrays.toString(courses));
        System.out.println(list);
        System.out.println(maps);
        System.out.println(sets);
        System.out.println(courselist);
    }
}

Course类:

package com.dragon.spring5.collectiontype;

public class Course {
    private String cname;

    public void setCname(String cname) {
        this.cname = cname;
    }

    @Override
    public String toString() {
        return "Course{" +
                "cname='" + cname + '\'' +
                '}';
    }
}

spring配置文件:

<bean id="stu" class="com.dragon.spring5.collectiontype.Stu">
        <property name="courses">
            <array>
                <value>java课程</value>
                <value>数据库课程</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>张三</value>
                <value>小三</value>
            </list>
        </property>
        
        
        <property name="maps">
            <map>
                <entry key="JAAVA" value="java"></entry>
                <entry key="PHP" value="php"></entry>
            </map>
        </property>


        <property name="sets">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
        <!--外部bean注入-->
        <property name="courselist">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
</bean>
<bean id="course2" class="com.dragon.spring5.collectiontype.Course">
       <property name="cname" value="MyBatis框架"></property>
</bean>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
        Stu stu=context.getBean("stu", Stu.class);
        stu.test();

在这里插入图片描述
集合提取出来注入:
用util标签(注意util标签怎么引入):
Book类:

package com.dragon.spring5.collectiontype;

import java.util.List;

public class Book {
    private List<String> list;

    public void setList(List<String> list) {
        this.list = list;
    }
    public void test(){
        System.out.println(list);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns: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="booklist">
            <value>易筋经</value>
            <value>九阳神功</value>
            <value>九阴真经</value>
        </util:list>
        <bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype">
            <property name="list" ref="booklist"></property>
        </bean>
</beans>

(5)FactoryBean(工厂bean)

普通bean在配置文件中定义的bean类型就是返回类型。而工厂bean在配置文件定义的bean类型可以和返回类型不一样。
下面的MyBean类中实现FactoryBean接口,重写getObject,getObjectType方法。
这里把getObject重写成返回Course对象的方法。

package com.dragon.spring5.factorybean;

import com.dragon.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<Course> {

    @Override
    public Course getObject() throws Exception {
        Course course=new Course();
        course.setCname("abc");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

spring配置文件:

<bean id="mybean" class="com.dragon.spring5.factorybean.MyBean"></bean>

测试:
注意这里实例化对象不是MyBean类型,是上面getObject方法返回的对象类型。

		ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
        Course course=context.getBean("mybean", Course.class);
        System.out.println(course);

在这里插入图片描述

2.bean的作用域

  • 在Spring中,默认情况下bean创建的是单实例对象:
 		ApplicationContext context1=new ClassPathXmlApplicationContext("bean4.xml");
        Book book1=context1.getBean("book", Book.class);
        Book book2=context1.getBean("book", Book.class);

在这里插入图片描述
可以看出地址一样

  • bean有个属性是scope,可以通过设置成singleton或prototype来决定其是单实例还是多实例(1)singleton:默认值,表示单实例对象。加载配置文件时就会创建单实例对象。
    (2)prototype:表示多实例对象。不是在加载配置文件时创建对象,在调用getBean方法时创建多实例对象。
<bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype">
            <property name="list" ref="booklist"></property>
</bean>

在这里插入图片描述

  • scope的值还可以是request、session(大家应该知道这两个值的作用域吧)

3.bean的生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
下面提供大家测试需要用的类,方便大家理解:
Orders类:

package com.dragon.spring5.bean;

public class Orders {
    private String oname;

    public Orders() {
        System.out.println("第一步 执行无参数构造创建bean实例");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步 调用set方法设置属性值");
    }

    public void initMethod(){
        System.out.println("第三步 执行初始化方法");
    }
    public void destoryMethod(){
        System.out.println("第五步 bean销毁的方法");
    }
}

后置处理器:

package com.dragon.spring5.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法");
        return bean;
    }
}

测试:

package com.dragon.spring5.testDemo;

import com.dragon.spring5.bean.Orders;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean6.xml");
        Orders orders=context.getBean("orders", Orders.class);
        System.out.println("第四步 获取创建beam实例对象");
        System.out.println(orders);
        context.close();
    }
}

spring配置文件:

        </bean>
<!--        后置处理器-->
        <bean id="myBeanPost" class="com.dragon.spring5.bean.MyBeanPost"></bean>

在这里插入图片描述

4.xml自动配置属性值

bean标签属性autowire两个常用值:
(1)byName:根据属性名称注入,注入值bean的id值和类属性名称一样
(2)byType:根据属性类型注入
spring配置文件:
(Emp类中有dept属性)

<bean id="emp" class="com.dragon.spring5.autowrite.Emp">
                <property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

正常情况下属性值需要用property标签注入。
而用autowire,可以自动注入

        <bean id="emp" class="com.dragon.spring5.autowrite.Emp" autowire="byName"></bean>
        <bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

5.外部属性文件操作bean

这里用连接数据库举例:
在resource文件夹内jdbc属性文件(jdbc.properties)

pro.driverClass=com.mysql.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/?(这个根据自己数据库配置)
pro.username=root
pro.password=root

spring配置文件(注意context配置,这里使用的< context:property-placeholder/ >标签引入属性文件,其中classpath就是配置属性文件的全称):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${pro.driverClass}"></property>
                <property name="url" value="${pro.url}"></property>
                <property name="username" value="${pro.username}"></property>
                <property name="password" value="${pro.password}"></property>
        </bean>
</beans>

四、注解实现bean管理

1.基于注解创建对象

spring提供四种创建对象的注解(下面四个注解说的一般使用在哪层是约定俗成的,其实效果都一样,都可以混用):

  • @Component
  • @Service:一般用于业务逻辑或Service层
  • @Controller:一般用于web层
  • @ Repository:一般用于Dao层
    步骤:
    (1)引入依赖(开头已告知所有maven依赖库)
    (2)开启组件扫描:扫描base-package包下所有有注解的类并为其创建对象
<context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>

代表扫描com.dragon.spring5_1下的所有文件,找寻有注解的文件,然后创建实例。
(2)创建类并在类上创建对象注解

@Service(value = "userService")
public class UserService {
    public void add(){
        System.out.println("service add.......");
    }
}

测试:

        ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");
        UserService userService=context.getBean("userService",UserService.class);
        System.out.println(userService);
        userService.add();

在这里插入图片描述

2.组件扫描细节

还有两种用法:

        设置不扫描的注解
    	<context:component-scan base-package="com.dragon.spring5_1">
                <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        </context:component-scan>
		设置扫描的注解
        <context:component-scan base-package="com.dragon.spring5_1" use-default-filters="false">
                <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        </context:component-scan>

3.基于注解进行属性注入

  • @Autowired:根据属性类型自动装配
  • @Qualifier:根据属性名称自动装配,需要和@Autowired一起使用
    当遇到一个接口有很多实现类时,只通过@Autowire是无法完成自动装配的,所以需要再使用@Qualifier通过名称来锁定某个类
  • @Resource:可以根据类型注入,也可以根据名称注入(不常用)
  • @Value:注入属性值
    实例:
    UserDao、UserDaoImpl、UserService类:
package com.dragon.spring5_1.dao;

import org.springframework.stereotype.Repository;

public interface UserDao {
    public void add();
}
==================================================
package com.dragon.spring5_1.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("dao add......");
    }
}
=========================================================
package com.dragon.spring5_1.service;

import com.dragon.spring5_1.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service(value = "userService")
public class UserService {
    @Value(value = "abc")
    private String name;
    @Autowired
    @Qualifier(value ="userDaoImpl1")
    private UserDao userDao;
    public void add(){
        System.out.println("service add......."+name);
        userDao.add();
    }
}

spring配置文件:

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

        <context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>
</beans>

测试:

	ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");
        UserService userService=context.getBean("userService",UserService.class);
        System.out.println(userService);
        userService.add();

在这里插入图片描述

五、完全注解开发

上面讲诉后,完全注解开发应该是最简洁的。来个实例看一看。
这时要引入配置类来代替spring配置文件,来实现组件扫描不用xml配置,进而实现完全注解开发。
配置类:

package com.dragon.spring5_1.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//配置类
@ComponentScan(basePackages = {"com.dragon.spring5_1"})//配置扫描的文件
public class SpringConfig {

}

测试(UserDao、UserDaoImpl、UserService还是上面基于注解属性注入例子的):

package com.dragon.spring5_1.testDemo;

import com.dragon.spring5_1.config.SpringConfig;
import com.dragon.spring5_1.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class test2 {
    public static void main(String[] args) {
    	//注意new的对象变了,变成了AnnotationConfigApplicationContext
        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService=context.getBean("userService", UserService.class);
        System.out.println(userService);	
        userService.add();

    }
}

六、AOP概述和原理

用的依赖(包括上篇文章讲诉的IOC依赖):

       <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.19</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.1.3</version>
        </dependency>

1.概述和原理

  • AOP:面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗来说就是在不修改代码的情况下添加新的功能。
  • 底层通过动态代理实现:
    (1)有接口情况:使用JDK动态代理,即创建接口实现类的代理对象。
    (2)无接口情况:使用CGLIB动态代理,即创建当前类子类的代理对象。

2.JDK动态代理实例

核心:

  • 通过 java.lang.reflect.Proxy类 的 newProxyInstance方法 创建代理类。
  • newProxyInstance方法
    在这里插入图片描述
    参数一:类加载器
    参数二:所增强方法所在的类,这个类实现的接口,支持多个接口
    参数三:实现InvocationHandle接口,重写invoke方法来添加新的功能
    模拟代理:
    UserDao、UserDaoImpl类:
package com.dragon.springaop;

public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}
================================================
package com.dragon.springaop;

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a,int b) {
        System.out.println("add方法执行了...");
        return a+b;
    }

    @Override
    public String update(String id) {
        System.out.println("update方法执行了...");
        return id;
    }
}

JDKProxy类(通过 java.lang.reflect.Proxy类 的 newProxyInstance方法创建代理类):

package com.dragon.springaop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces={UserDao.class};//创建接口实现类代理对象
        UserDaoImpl userDao=new UserDaoImpl();
        UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao)) ;
        int result=dao.add(1,2);
        System.out.println("result:"+result);
    }
}
class UserDaoProxy implements InvocationHandler{

    //创建的是谁的代理对象,把谁传递过来
    //有参构造传递
    private Object obj;
    public UserDaoProxy (Object obj){
        this.obj=obj;
    }
	//参数含义:代理对象、方法、参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法之前执行...."+ method.getName()+":传递参数...."+ Arrays.toString(args));
        Object res=method.invoke(obj,args);
        System.out.println("方法之后执行...."+obj);
        return res;
    }
}

在这里插入图片描述
其实JDK动态代理本质就是在原来要增强的方法前面或后面增加一些逻辑处理等,而不修改源代码。从上面运行结果看以看出,add方法执行结果是3,但是在执行add方法执行多一些语句输出,这些就是我们增加的逻辑处理部分。其中method.invoke()就是模拟的原add方法执行,而前后的输出语句是模拟的增强的代码

七、基于AspectJ实现的AOP操作

1.什么是AspectJ

AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。

2.AOP相关术语

  • 连接点:类中可以被增强的方法,称为连接点。
  • 切入点:实际被增强的方法,称为切入点。
  • 通知:增强的那一部分逻辑代码。通知有多种类型:
    (1)前置通知:增强部分代码在原代码前面。
    (2)后置通知:增强部分代码在原代码后面。
    (3)环绕通知:增强部分代码既有在原代码前面,也有在原代码后面。
    (4)异常通知:原代码发生异常后才会执行。
    (5)最终通知:类似与finally那一部分
  • 切面:指把通知应用到切入点这一个动作。

3.切点表达式

  • 语法:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
  • 例1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.auguigu.dao.BookDao.add(..))
  • 例2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
  • 例3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))

3.基于注解方式实现

(1)实例:

User:
注解方式创建User对象user

package com.dragon.springaop.anno;

import org.springframework.stereotype.Component;

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

UserProxy类(先忽略@Order注解):
注解方式创建UserProxy对象userProxy
@Aspect定义UserProxy为切面类(即指把通知应用到切入点的类)

package com.dragon.springaop.anno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect//定义切面类
@Order(3)
public class UserProxy {
    @Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void before(){
        System.out.println("before.....");
    }
    @AfterReturning(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning....");
    }
    @After(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void after(){
        System.out.println("after....");
    }
    @AfterThrowing(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing....");
    }
    @Around(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("环绕之前....");
            proceedingJoinPoint.proceed();
        System.out.println("环绕之后....");
    }
}

spring配置文件:

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
                                http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd">
         <!--开启组件扫描-->
        <context:component-scan base-package="com.dragon.springaop.anno"/>
        <!--开启AspectJ生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试:

 	ApplicationContext context=new ClassPathXmlApplicationContext("beanaop1.xml");
        User user=context.getBean("user", User.class);
        user.add();

在这里插入图片描述
可以看出Befoe(前置通知,在add前运行)、AfterRetruning(后置通知或返回通知,在add返回值后运行)、AfterThrowing(异常通知,在add出现异常后,这个没有运行,因为没异常,大家在add内添加 int i=1/0 测试一下,不在演示)、After(最终通知,在add执行完后)、Around(环绕通知,在add前和后)的运行时期。

(2)切入点提取

上面的UserProxy 类中有很多重复的切入点表达式,可以进行公共提取

@Pointcut(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void pointDemo(){    
}

//前置通知
@Before(value="pointDemo()")
public void before(){
    System.out.println("before....");
}

(3)设置增强类优先级

上面的实例只有UserProxy一个增强类,当有多个增强类时,可以使用@Order(数值)设置优先级执行。(数字越小优先级越高)
在上诉例子中多创建一个PeopleProxy类,设置@Order:

package com.dragon.springaop.anno;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(1)
public class PersionProxy {
    @Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void persionBefore(){
        System.out.println("persionBefore.....");
    }
}

上面的UserProxy类中我设置的是Order(3),所以PeopleProxylei类先运行。
在这里插入图片描述

(4)完全注解开发

AOPConfig类:

package com.dragon.springaop.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = {"com.dragon.springaop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}

Book、BookProxy:

package com.dragon.springaop.aopxml;

import org.springframework.stereotype.Component;

@Component
public class Book {
    public void buy(){
        System.out.println("buy......");
    }
}

========================================
package com.dragon.springaop.aopxml;

public class BookProxy {
    public void before(){
        System.out.println("before....");
    }
}

测试:

		ApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);
        Book book=context.getBean("book", Book.class);
        book.buy();

4.基于xml配置文件实现(了解)

Book、BookProxy:

package com.dragon.springaop.aopxml;

import org.springframework.stereotype.Component;

public class Book {
    public void buy(){
        System.out.println("buy......");
    }
}

========================================
package com.dragon.springaop.aopxml;

public class BookProxy {
    public void before(){
        System.out.println("before....");
    }
}

spring配置文件:

 <bean id="book" class="com.dragon.springaop.aopxml.Book"></bean>
    <bean id="bookProxy" class="com.dragon.springaop.aopxml.BookProxy"></bean>

<!--    配置aop增强-->
    <aop:config>
<!--        切入点-->
        <aop:pointcut id="p" expression="execution(* com.dragon.springaop.aopxml.Book.buy(..))"/>
<!--        配置切面-->
        <aop:aspect ref="bookProxy">
<!--            增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("beanaop2.xml");
        Book book=context.getBean("book", Book.class);
        book.buy();

八、JdbcTemplate

1.相关依赖(AOP、IOC、JdbcTemplate都有)

        <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>19</maven.compiler.source>
        <maven.compiler.target>19</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.19</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>compile</scope>
        </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.19</version>
            </dependency>
    </dependencies>
</project>

2.代码实战

(1)方法讲解

  • 增删改:
int update(String sql, Object... args);
  • 查询(返回某个值):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回某个对象):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回集合):
List<T> query(String sql,RowMapper<T> rowMapper,Object... args);
  • 批量增删改:
int[] batchUpdate(String sql,List<Object[]> batchArgs);

(2)代码实例

实体层——Book实体类:

package com.dragon.jdbc.entity;

public class Book {
    private String bookId;
    private String bookname;
    private String bstatus;

    public String getBookId() {
        return bookId;
    }

    public String getBookname() {
        return bookname;
    }

    public String getBstatus() {
        return bstatus;
    }

    public void setBookId(String bookId) {
        this.bookId = bookId;
    }

    public void setBookname(String bookname) {
        this.bookname = bookname;
    }

    public void setBstatus(String bstatus) {
        this.bstatus = bstatus;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId='" + bookId + '\'' +
                ", bookname='" + bookname + '\'' +
                ", bstatus='" + bstatus + '\'' +
                '}';
    }
}

Dao层——BookDao类:

package com.dragon.jdbc.dao;

import com.dragon.jdbc.entity.Book;

import java.util.List;

public interface BookDao {
    public void add(Book book);//添加
    public void update(Book book);//修改更新
    public void delete(String id);//删除
    public int selectCount();//查找数量,返回int类型
    public Book findBookInfo(String id);//根据id查找某本书,返回对象
    public List<Book> findAllBook();//查找数据库内所有对象,返回集合
    public void bathAddBook(List<Object[]> bathArgs);//批量添加
    public void bathUpdateBook(List<Object[]> bathArgs);//批量修改
    public void bathDeleteBook(List<Object[]> bathArgs);//批量删除
}

BookDao实现类BookDaoImpl:

package com.dragon.jdbc.dao;

import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Arrays;
import java.util.List;

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

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

    @Override
    public void update(Book book) {
        String sql="update t_book set bookname=?,bstatus=? where book_id=?";
        Object[] args={book.getBookname(),book.getBstatus(),book.getBookId()};
        int update=jdbcTemplate.update(sql,args);
        System.out.println(update);
    }

    @Override
    public void delete(String id) {
        String sql="delete from t_book where book_id=?";
        int update=jdbcTemplate.update(sql,id);
        System.out.println(update);
    }

    @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 book_id=?";
        Book book= jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);
        return book;
    }

    @Override
    public List<Book> findAllBook() {
        String sql="select * from t_book";
        List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
        return bookList;
    }

    @Override
    public void bathAddBook(List<Object[]> bathArgs) {
        String sql="insert into t_book values(?,?,?)";
        int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
        System.out.println(Arrays.toString(ints));
    }

    @Override
    public void bathUpdateBook(List<Object[]> bathArgs) {
        String sql="update t_book set bookname=?,bstatus=? where book_id=?";
        int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
        System.out.println(Arrays.toString(ints));
    }

    @Override
    public void bathDeleteBook(List<Object[]> bathArgs) {
        String sql="delete from t_book where book_id=?";
        int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
        System.out.println(Arrays.toString(ints));
    }


}

service层——BookService:

package com.dragon.jdbc.service;

import com.dragon.jdbc.dao.BookDao;
import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

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

    public void addBook(Book book){
        bookDao.add(book);
    }
    public void updateBook(Book book){
        bookDao.update(book);
    }
    public void deleteBook(String id){
        bookDao.delete(id);
    }
    public int findCount(){
       return bookDao.selectCount();
    }
    public Book finOne(String id){
        return bookDao.findBookInfo(id);
    }
    public List<Book> findAll(){
        return bookDao.findAllBook();
    }
    public void bathAdd(List<Object[]> bathArgs){
        bookDao.bathAddBook(bathArgs);
    }
    public void bathUpdate(List<Object[]> bathArgs){
        bookDao.bathUpdateBook(bathArgs);
    }
    public void bathDelete(List<Object[]> bathArgs){
        bookDao.bathDeleteBook(bathArgs);
    }
}

数据库连接配置——Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${pro.driverClass}"></property>
                <property name="url" value="${pro.url}"></property>
                <property name="username" value="${pro.username}"></property>
                <property name="password" value="${pro.password}"></property>
        </bean>
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"></property>
        </bean>
        <context:component-scan base-package="com.dragon.jdbc"></context:component-scan>
</beans>

properties配置文件——jdbc.properties:
需要自行修改数据库名称(我的是user_db)

pro.driverClass=com.mysql.cj.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
pro.username=root
pro.password=root

测试类:

package com.dragon.jdbc.test;

import com.dragon.jdbc.entity.Book;
import com.dragon.jdbc.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.List;

public class test1 {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean8.xml");
        BookService bookService=context.getBean("bookService",BookService.class);
//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("java");
//        book.setBstatus("a");
//        bookService.addBook(book);

//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("javaup");
//        book.setBstatus("a");
//        bookService.updateBook(book);

//        bookService.deleteBook("1");

//        System.out.println( bookService.findCount());

//        Book book=bookService.finOne("1");
//        System.out.println(book);

//        System.out.println(bookService.findAll());

//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"3","java","j"};
//        Object[] o2={"4","c++","c"};
//        Object[] o3={"5","MySql","m"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathAdd(bathArgs);

//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"java001","j","3"};
//        Object[] o2={"c++002","c","4"};
//        Object[] o3={"MySql003","m","5"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathUpdate(bathArgs);

        List<Object[]> bathArgs=new ArrayList<>();
        Object[] o1={"3"};
        Object[] o2={"4"};
        bathArgs.add(o1);
        bathArgs.add(o2);
        bookService.bathDelete(bathArgs);
    }

}

九、事务及其参数含义

1.事务的四个特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性。

2.事务的传播行为(propagation)

Spring定义了7种传播行为:

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED当前方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行

在这里插入图片描述
这里只图解介绍一个,其他类推

3.事务隔离性

  • 脏读:一个未提交事务读取到另一个未提交事务的数据
    例:事务A读取到事务B修改后的数据,但是读取后事务B回滚了,此时A读取的是修改后的数据,但是修改撤销了。
  • 不可重复读:一个未提交的事务读取到另一个提交事务修改数据
    例:事务A和事务B读取同一个数据,但是事务B在读取后进行修改,然后提交,提交后事务A又读取这个数据,此时读取的是修改后的,跟上次读取的不一样。
  • 幻读(虚读):一个未提交的事务读取到另一个提交事务添加数据

4.事务的隔离级别(ioslation)

在这里插入图片描述

5.timeout(超时)

事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。

6.readOnly(是否只读)

读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。

7.rollbackFor(回滚)

设置出现哪些异常进行事务回滚。

8.noRollbackFor(不回滚)

设置出现哪些异常不进行事务回滚。

十、事务管理

Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。
在这里插入图片描述

1.事务管理的两种形式

  • 编程式事务管理
    例:
        try{
            //开启事务

            //进行业务操作
            userDao.reduceMoney();
            //模拟异常
            int i=10/0;
            userDao.addMoney();
            //没出现异常,事务提交
        }catch (Exception e){
            //异常,事务回滚
        }
  • 声明式事务管理(AOP原理)
    例:
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
    @Autowired
    private UserDao userDao;
    public void accountMoney(){
        userDao.reduceMoney();
        int i= 1 / 0;
        userDao.addMoney();
    }
}

2.注解实现声明式事务管理

就是上述声明式管理的例子,这里补充一下全部代码:

================userDao====================
package com.dragon.shiwu.dao;

public interface UserDao {
    public void addMoney();
    public void reduceMoney();
}
==============userDaoImpl===================
package com.dragon.shiwu.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

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

    @Override
    public void addMoney() {
        String sql="update t_account set money=money + ? where username = ?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void reduceMoney() {
        String sql="update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }
}
==============userService============================
package com.dragon.shiwu.service;

import com.dragon.shiwu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
    @Autowired
    private UserDao userDao;
    public void accountMoney(){
        userDao.reduceMoney();
        int i= 1 / 0;
        userDao.addMoney();
    }
}
============Spring配置文件===========================(注意这里引入了tx命名空间和)
<?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"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${pro.driverClass}"></property>
                <property name="url" value="${pro.url}"></property>
                <property name="username" value="${pro.username}"></property>
                <property name="password" value="${pro.password}"></property>
        </bean>
<!--创建JdbcTemplate对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
                <property name="dataSource" ref="dataSource"></property>
        </bean>
        <context:component-scan base-package="com.dragon.shiwu"></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>
</beans>

运行前:
在这里插入图片描述
运行后:
在这里插入图片描述
在这里插入图片描述

3.xml实现声明式事务管理

Spring配置文件:

<?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                                 http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${pro.driverClass}"></property>
        <property name="url" value="${pro.url}"></property>
        <property name="username" value="${pro.username}"></property>
        <property name="password" value="${pro.password}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    开启组件扫描-->
    <context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
    <!--配置事务通知-->
    <tx:advice id="txadvice">
        <tx:attributes>
            <!--配置事务参数-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--    配置切入点和切面-->
    <aop:config>
<!--        配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/>
<!--        配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

4.完全注解开发

TxConfig类:

package com.dragon.shiwu.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration//配置类
@ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

}

测试类:

package com.dragon.shiwu.test;

import com.dragon.shiwu.config.TxConfig;
import com.dragon.shiwu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class test2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService",UserService.class);
        userService.accountMoney();
    }
}


总结

以上就是Spring的全部详细讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1322327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Server 查询处理过程

查询处理--由 SQL Server 中的关系引擎执行&#xff0c;它获取编写的 T-SQL 语句并将其转换为可以向存储引擎发出请求并检索所需结果的过程。 SQL Server 需要四个步骤来处理查询&#xff1a;分析、代化、优化和执行。 前三个步骤都由关系引擎执行&#xff1b;第三步输出的是…

一文解释JS如何获取当前系统电量

在前端浏览器中我们可以通过使用JavaScript的navigator.getBattery()方法来获取当前系统的电池情况。 这个API可以监测设备的电池状态&#xff0c;包括是否在充电、当前电量以及放电或充电所需的时间。本文将介绍如何使用这个API以及它在实际应用中的使用。 API使用 首先让我…

SD-WAN组网:企业网络的首选

在互联网技术不断更新、发展的背景之下&#xff0c;企业在面对日益复杂的网络组网需求时迫切需要一种创新的解决方案。传统的MPLS-VPN组网方式由于其高成本的特点令企业难以破局&#xff0c; SD-WAN正逐渐代替它们&#xff0c;成为企业网络组网的首选。 本文将深入探讨SD-WAN技…

广州华锐互动VRAR:利用VR开展新能源汽车触电安全演练,降低培训成本和风险

随着新能源汽车行业的快速发展&#xff0c;相关的安全培训也变得越来越重要。其中&#xff0c;触电急救培训对于保障驾驶员和乘客的安全具有重要意义。传统培训方式存在一些不足&#xff0c;而利用VR技术进行培训则具有很多优势。 利用VR技术开展新能源汽车触电安全演练可以在模…

电脑风扇控制软件Macs Fan Control mac支持多个型号

Macs Fan Control mac是一款专门为 Mac 用户设计的软件&#xff0c;它可以帮助用户控制和监控 Mac 设备的风扇速度和温度。这款软件允许用户手动调整风扇速度&#xff0c;以提高设备的散热效果&#xff0c;减少过热造成的风险。 Macs Fan Control 可以在菜单栏上显示当前系统温…

linux | sed 命令使用 | xargs命令 使用

##################################################### sed命令来自英文词组stream editor的缩写&#xff0c;其功能是利用语法/脚本对文本文件进行批量的编辑操作。sed命令最初由贝尔实验室开发&#xff0c;后被众多Linux系统集成&#xff0c;能够通过正则表达式对文件进行批…

Mysql利用备份数据恢复单表

1、说明 之前的备份是使用Xtrabackup8做的备份 使用了独立表空间(innodb_file_per_table1)&#xff0c;就可以单独恢复这个表。 2、在备份的目录下执行Prepare 根据自己之前备份的目录&#xff0c;选择执行路径 我之前的备份目录是 /tmp/backup/2023-12-16/full cd /tmp/…

虾皮 选品:如何在虾皮平台上进行有效的选品?

在虾皮&#xff08;Shopee&#xff09;这个跨境电商平台上&#xff0c;选品对于卖家来说至关重要。选品决定了店铺的销售额和竞争力。为了帮助卖家进行选品&#xff0c;虾皮平台提供了一些免费的选品工具&#xff0c;如知虾。同时&#xff0c;还有一些第三方选品工具&#xff0…

全国县级行政区点位数据,Shp+excel格式

基本信息. 数据名称: 县级行政区点位 数据格式: Shpexcel 数据时间: 2021年 数据几何类型: 点 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1xzqhdm_1省代码2xzqhmc_1省名称3xzqhdm_2市代码4xzqhmc_2市代…

pycharm设置自定义的代码颜色

1.最快的方法&#xff0c;选一个自己喜欢的主题&#xff0c;再对细节进行修改&#xff0c;操作如下&#xff0c;file->setting->Editor->ColorScheme->Language Defaults->Scheme。 在选好的主题上自定义自己喜欢的代码颜色&#xff0c;这里本人将自己自定义的函…

文献速递:生成对抗网络医学影像中的应用——基于生成对抗网络的医学图像处理:系统综述

本周给大家分享文献的主题是生成对抗网络&#xff08;Generative adversarial networks, GANs&#xff09;在医学影像中的应用。文献的研究内容包括同模态影像生成、跨模态影像生成、GAN在分类和分割方面的应用等。生成对抗网络与其他方法相比展示出了优越的数据生成能力&#…

你是无醇葡萄酒的爱好者吗?

不含酒精的蒸馏酒和起泡酒正在流行&#xff0c;尽管它们是葡萄酒市场中最小的细分市场之一&#xff0c;但需求和供应都在稳步增长。这是因为&#xff0c;和啤酒一样&#xff0c;消费者越来越多地询问无醇葡萄酒。 来自云仓酒庄品牌雷盛红酒分享不含酒精的酒好喝吗&#xff1f;尼…

Flink实时电商数仓(二)

GitLab的用户创建和推送 在root用户-密码界面重新设置密码添加Leader用户和自己使用的用户使用root用户创建相应的群组使用Leader用户创建对应的项目设置分支配置为“初始推送后完全保护”设置.gitignore文件&#xff0c;项目配置文件等其他非通用代码无需提交安装gitlab proj…

【python VS vba】(9) 在python使用matplotlib库来画多个图形,子图,以及图中图

2 用matplotlib 画多个函数图形 2.1 在一个画布里画多个图形 &#xff08;1张画布&#xff0c;1个坐标轴系&#xff0c;多个图形叠在一起&#xff09; import numpy as np import matplotlib.pyplot as pltfig1plt.figure(num1)xnp.linspace(-5,5, 10) yx*21 y2x**2# 绘图 p…

人工智能在约会APP开发中的作用

约会APP已成为当今技术世界中结识人们的流行方式。这意味着您不必要求您的朋友去见某人约会。简而言之&#xff0c;技术改善了约会过程&#xff0c;而人工智能在约会APP开发中的兴起极大地影响了人们今天的约会方式。 在约会APP中使用人工智能技术可以改善个人寻找完美匹配对象…

基于hfl/rbt3模型的情感分析学习研究——文本挖掘

参考书籍《HuggingFace自然语言处理详解 》 什么是文本挖掘 文本挖掘&#xff08;Text mining&#xff09;有时也被称为文字探勘、文本数据挖掘等&#xff0c;大致相当于文字分析&#xff0c;一般指文本处理过程中产生高质量的信息。高质量的信息通常通过分类和预测来产生&…

基于Java SSM框架实现宠物医院信息管理系统项目【项目源码】

基于java的SSM框架实现宠物医院信息管理系统演示 java简介 Java语言是在二十世纪末由Sun公司发布的&#xff0c;而且公开源代码&#xff0c;这一优点吸引了许多世界各地优秀的编程爱好者&#xff0c;也使得他们开发出当时一款又一款经典好玩的小游戏。Java语言是纯面向对象语言…

一键修复找不到msvcp140.dll无法继续执行代码的办法,有效修复

电脑出现“找不到msvcp140.dll无法继续执行代码”是什么情况&#xff1f;如果系统中没有这个文件或文件发生损坏&#xff0c;那么在启动某些应用程序或游戏时&#xff0c;可能会遇到错误消息&#xff0c;如“程序无法启动因为msvcp140.dll丢失在您的计算机上”或“找不到msvcp1…

CPU缓存一致性问题

什么是可见性问题&#xff1f; Further Reading &#xff1a;什么是可见性问题&#xff1f; 缓存一致性 内存一致性 内存可见性 顺序一致性区别 CPU缓存一致性问题 由于CPU缓存的出现&#xff0c;很好地解决了处理器与内存速度之间的矛盾&#xff0c;极大地提高了CPU的吞吐能…

luttuce(RedisTempate)实现hash(动态数据) expire lua脚本

话不多说先放脚本&#xff1a; local argv ARGV local length #argv if length > 0 then local unpackArgs {} for i 1, length - 1 dotable.insert(unpackArgs, argv[i]) end if redis.call(exists, KEYS[1]) 1 thenredis.call(del, KEYS[1])redis.call(hset, KEYS[…