Spring笔记


typora-root-url: assets
typora-copy-images-to: assets

Spring

1.Spring简介

主要缔造者,著名的Spring之父,Rod Johnson,非常有意思的是他是计算机本科,音乐博士学位

他是轮子理论的推崇者

轮子理论 :不要重复的造轮子(意思就是直接用写好的代码,不要每次都重新写一样的代码,不重新发明技术,而是让原有的技术使用起来更加方便)

Spring不像Mybatis那样是属于哪一层的框架,它存在 “everywhere”

2.Spring三大核心

  1. IOC/DI (控制反转/依赖注入)
  2. AOP 面向切面编程
  3. 声明式事务

3.Spring模块

Spring框架的功能被有组织的分散到约20个模块中。这些模块分布在核心容器,数据访问/集成,Web,AOP(面向切面的编程),植入(Instrumentation),消息传输和测试,如下面的图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tU5uhv6y-1573126039702)(/spring-overview.png.pagespeed.ce.XVe1noRCMt.png)]

Test :测试单元模块,用来处理测试用例

Core Container : 核心容器模块 ,使用Spring最基础的条件,不可或缺

  • 1.Beans : 负责创建对象和管理对象
  • 2.Core : 核心类,提供一些核心类库
  • 3.Context : 上下文参数,获取外部资源,或者管理注解等
  • 4.SpEL : 表达式语言,对应expression.jar包

AOP : 实现AOP功能需要的依赖

Aspects : 切面,AOP 依赖包

Instrumentation : 工具类

Messaging : 消息处理

Data Access/Integration : spring封装数据访问层内容

  • 1.JDBC : Spring对JDBC的封装
  • 2.ORM:封装了持久层框架的代码,例如Hibernate(但并没有对Mybatis进行封装)
  • 3.Transactions :对应soring-tx.jar,声明式事务时需要导入

Web : 需要完成Web相关功能时需要,例如:需要Tomcat加载Spring配置文件时需要

4.Spring之IOC/DI

IOC (Inversion of Control) 控制反转

IOC是什么 :原来由程序员主动 new 对象这一行为转交给Spring负责(即对象的控制权反转了)

IOC的作用 :解耦(程序员不需要管理对象,解开了程序员与对象的耦合)

例如我们都学过Mybatis,经历过创建工厂对象,获取sqlSession,这些管理对象的代码如果用Spring去管理将大大便利我们的开发

DI依赖注入是什么 :它本质上与IOC完全一样,只是角度不同,对于原有的应用程序来说对象的控制权反转了,但对于spring容器来说,相当于spring在向一个类中注入对象

5.IOC/DI初体验

5.1引入依赖

创建maven项目,引入依赖

<?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.neuedu</groupId>
    <artifactId>spring_yzn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- 核心容器 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
    </dependencies>
</project>
5.2创建实体类
package org.neuedu.spring;

public class Student {
    private int stuno;
    private String name;

    public int getStuno() {
        return stuno;
    }

    public void setStuno(int stuno) {
        this.stuno = stuno;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
5.3创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
    xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
            着在根节点中能使用什么样的便签以完成不同的配置
 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="stu" class="org.neuedu.spring.Student"></bean>
</beans>

日志配置文件log4j.properties

log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
5.4创建测试类StudentTest.java
package org.neuedu.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StudentTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = applicationContext.getBean("stu", Student.class);
        System.out.println(stu);
    }
}

控制台打印,没有输出NULL说明对象已经创建出来了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WnWLO4g-1573126039706)(/1570451511680.png)]在实体类中我们并没有添加任何构造器,所以Spring创建对象默认选择的是无参构造器,可以自己测试一下

在这个示例中,貌似Spring造成我们在获取对象时,反倒代码多了,但是想象一下,如果这个对象在100个类中被调用,当需要修改时,使用Spring只需要修改一下配置文件便可,而以前却需要一个一个去修改,从这个角度看,使用Spring是非常必要的,但上述示例只是一个简单的例子,Spring虽然能管理所有对象,但在项目中也是分场景使用的,不是什么对象都一定要用Spring管理的,杀鸡焉用牛刀的道理相信大家都明白的

5.5创建对象的三种方式(了解)
5.5.1通过构造方法创建(有参,无参)

在上述示例中

<?xml version="1.0" encoding="UTF-8"?>
<!--
    xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
            着在根节点中能使用什么样的便签以完成不同的配置
 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="stu" class="org.neuedu.spring.Student"></bean>
</beans>

采取的默认无参构造器创建的对象,如何指定有参构造器创建对象呢?非常简单

添加有参构造器

package org.neuedu.spring;

public class Student {
    private int stuno;
    private String name;
    public Student() {}
    public Student(int stuno, String name) {
        this.stuno = stuno;
        this.name = name;
    }
}

修改配置xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
    xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
            着在根节点中能使用什么样的便签以完成不同的配置
 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="stu" class="org.neuedu.spring.Student">
        <constructor-arg name="stuno" value="1001"></constructor-arg>
        <constructor-arg name="name" value="tom"></constructor-arg>
    </bean>
</beans>

测试类

package org.neuedu.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StudentTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = applicationContext.getBean("stu", Student.class);
        System.out.println(stu.getName());
    }
}

控制台

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zn6nFYQn-1573126039708)(/1570451598830.png)]

5.5.2实例工厂

需要创建工厂对象,然后让工厂帮助我们创建对象

工厂类

public class StudentFactory {
    public Student getInstance(){
        return new Student(1002,"mike");
    }
}

配置文件

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

    <!--工厂对象-->
    <bean class="org.neuedu.spring.StudentFactory" id="factory"></bean>
    <bean id="stu" factory-bean="factory" factory-method="getInstance"></bean>

</beans>

测试类

package org.neuedu.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StudentTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = applicationContext.getBean("stu", Student.class);
        System.out.println(stu.getName());
    }
}

启动测试

5.5.3静态工厂

不需要创建工厂对象,直接调用工厂方法创建对象

将上述实例工厂稍加改造就是静态工厂

package org.neuedu.spring;

public class StudentFactory {
    public static Student getInstance(){
        return new Student(1002,"mike");
    }
}

配置文件

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

    <!--工厂对象-->
    <bean id="stu" class="org.neuedu.spring.StudentFactory" factory-method="getInstance"></bean>

</beans>

启动测试

5.6属性赋值

依赖注入有三种方式:构造器注入,setter注入,接口注入(Spring不支持)

5.6.1构造器赋值(注入)
<?xml version="1.0" encoding="UTF-8"?>
<!--
    xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
            着在根节点中能使用什么样的便签以完成不同的配置
 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="stu" class="org.neuedu.spring.Student">
        <constructor-arg name="stuno" value="1001"></constructor-arg>
        <constructor-arg name="name" value="tom"></constructor-arg>
    </bean>
</beans>
5.6.2setter方法赋值(注入)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--setter注入-->
    <bean id="stu" class="org.neuedu.spring.Student">
        <property name="stuno" value="123"></property>
        <property name="name" value="lilei"></property>
    </bean>
    <!--这样写也可以,与上面等效,二选一-->
    <bean id="stu" class="org.neuedu.spring.Student">
        <property name="stuno">
            <value>123</value>
        </property>
        <property name="name">
            <value>lilei</value>
        </property>
    </bean>

</beans>

启动测试

5.6.3各类属性赋值(注入)

Student.java

package org.neuedu.spring;

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

public class Student {
    private int stuno;
    private String name;
    private Set<String> set;
    private List<String> list;
    private String[] array;
    private Map<String,String> map;

    ...
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--这样写也可以-->
    <bean id="stu" class="org.neuedu.spring.Student">
        <property name="stuno">
            <value>123</value>
        </property>
        <property name="name">
            <value>lilei</value>
        </property>
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
                <value>set4</value>
            </set>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
        <property name="map">
            <map>
                <entry key="key1" value="value1"></entry>
                <entry key="key2" value="value2"></entry>
            </map>
        </property>
    </bean>

</beans>

还有一种特殊的类型properties,但代码不好演示,这里就单独列出来

<property name="properties">
    <props>
        <prop key="a">mysql</prop>
        <prop key="b">testurl</prop>
    </props>
</property>

类似于properties文件中的配置

a=mysql
b=testurl

意思就是properties文件中的配置信息,spring也可以配置类似于properties文件这种属性来完成特殊的功能需求,我们在后续会见到

注意:注入基本数据类型或String类型时,使用value进行注入,如果是另一个对象,需要使用ref注入,当使用ref时,依赖注入就发生了,但本身也是IOC的一种体现,所以IOC和DI本质上是一回事

package org.neuedu.spring;

public class Book {
    private String bookName;
	...
}
package org.neuedu.spring;

public class Student {
    private int stuno;
    private String name;
    private Book book;
	...
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="stu" class="org.neuedu.spring.Student">
        <property name="stuno">
            <value>123</value>
        </property>
        <property name="name">
            <value>lilei</value>
        </property>
        <property name="book">
            <!-- bean属性 对应另一个bean的id -->
            <ref bean="book111"></ref>
        </property>
    </bean>
    <bean id="book111" class="org.neuedu.spring.Book"></bean>
</beans>

6.Spring简单整合Mybatis

接下来我们来体验一下spring整合其他框架的魅力所在

6.1创建maven项目引入依赖
<?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.neuedn</groupId>
    <artifactId>spring-mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--spring 核心容器-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--spring jdbc 数据源需要-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--spring 事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--整合spring-mybatis的包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

####6.2创建applicationContext.xml

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

    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_yzn"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置SessionFactory-->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置mapper扫描器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 当ref关联的id也叫sqlSessionFactory会出现错误 -->
        <property name="sqlSessionFactory" ref="factory"></property>
        <!-- 与上一行代码等效,但不会出现错误,推荐使用 -->
        <property name="sqlSessionFactoryBeanName" value="factory"></property>
        <property name="basePackage" value="org.neuedu.mapper"></property>
    </bean>

    <bean id="userService" class="org.neuedu.service.UserService">
        <property name="userMapper" ref="userMapper"></property>
    </bean>
</beans>
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
6.3项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VARP971q-1573126039711)(/1570539624646.png)]

mapper和xml

package org.neuedu.mapper;
import org.neuedu.bean.User;
import java.util.List;

public interface UserMapper {
    List<User> getAllUser();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.neuedu.mapper.UserMapper">
    <select id="getAllUser" resultType="org.neuedu.bean.User">
        select * from `user`
    </select>
</mapper>

service

package org.neuedu.service;
import org.neuedu.bean.User;
import org.neuedu.mapper.UserMapper;
import java.util.List;

public class UserService {
    private UserMapper userMapper;

    public UserMapper getUserMapper() {
        return userMapper;
    }

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public List<User> getAllUser() {
        return userMapper.getAllUser();
    }
}

MainTest.java

package org.neuedu;

import org.neuedu.bean.User;
import org.neuedu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        UserService userService = applicationContext.getBean("userService", UserService.class);
        List<User> users = userService.getAllUser();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

运行测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXWEdvj9-1573126039713)(/1570539845747.png)]

事务和别名也可以配置,以后讲解

OK!!!现在我们只简单的整合了Mybatis,还不是最终版,后续在SSM整合时会更精简,但已经非常 easy 了不是么

7.AOP

Aspect Oriented Programming : 面向切面编程

针对某一个或一些方法,添加通知,形成横切面的思想就是AOP

简单程序

package org.neuedu;

public class AOPTest {
    public void test1() {
        System.out.println(1);
    }
    public void test2() {
        System.out.println(2);
    }
    public void test3() {
        System.out.println(3);
    }

    public static void main(String[] args) {
        AOPTest aopTest = new AOPTest();
        aopTest.test1();
        aopTest.test2();
        aopTest.test3();
    }
}

现在我们想在原有纵向执行流程中添加横向切面通知

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-02HFjEAN-1573126039715)(/1570541704421.png)]通知就是方法,只不过让它在执行test2前或后自动调用执行

7.1必备概念
  • 1.原有功能:切点,pointcut
  • 2.前置通知:在切点之前执行的功能,before advice
  • 3.后置通知:在切点之后执行的功能,afteradvice
  • 4.如果切点执行过程中出现异常,会触发异常通知 throw advice
  • 5.所有功能总称 切面
  • 6.把切面嵌入到原有功能的过程 称为 织入
7.2小试牛刀

#####7.2.1添加依赖

<?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.neuedu</groupId>
    <artifactId>aop</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--spring 核心容器-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--spring 事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <!--aop依赖jar-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
    </dependencies>

</project>
7.2.2准备代码
package org.neuedu;
public class AOPTest {
    public void test1() {
        System.out.println(1);
    }
    public void test2() {
        System.out.println(2);
    }
    public void test3() {
        System.out.println(3);
    }

    public static void main(String[] args) {
        // 注意:想要使用aop,必须是spring管理的对象,所以这里不能new
        
    }
}
7.2.3准备通知类
package org.neuedu;

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置通知");
    }
}
package org.neuedu;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class MyAfterAdvice implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后置通知");
    }
}
7.2.4配置文件
<?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
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="beforeAdvice" class="org.neuedu.MyBeforeAdvice"></bean>
    <bean id="afterAdvice" class="org.neuedu.MyAfterAdvice"></bean>
    <aop:config>
        <!--配置切面-->
        <aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>
        <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"></aop:advisor>
        <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

    <bean id="aopTest" class="org.neuedu.AOPTest"></bean>
</beans>
7.2.5测试
package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {
    public void test1() {
        System.out.println(1);
    }
    public void test2() {
        System.out.println(2);
    }
    public void test3() {
        System.out.println(3);
    }
    public static void main(String[] args) {
        // 使用aop,对象必须是spring管理的,所以这里不能new
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        AOPTest aopTest = applicationContext.getBean("aopTest", AOPTest.class);
        aopTest.test1();
        aopTest.test2();
        aopTest.test3();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7FNp4wpD-1573126039717)(/1570545487035.png)]

7.2.6*通配符的含义
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>

org.neuedu.AOPTest类下test2()方法

<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.*())"/>

org.neuedu.AOPTest类下的任意无参方法

<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.*(..))"/>

org.neuedu.AOPTest类下的任意方法

<aop:pointcut id="pointcut" expression="execution(* org.neuedu.*.*(..))"/>

org.neuedu包下的任意类任意方法

<aop:pointcut id="pointcut" expression="execution(* org.neuedu.*.service.*.*(..))"/>

org.neuedu包下的任意子包下service下任意类任意方法(这种配置在分组项目中是比较常见的)

7.2.7前置通知和后置通知参数(了解)
package org.neuedu;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置通知");
    }
}

Method method : 切点方法对象

Object[] objects :切点方法参数

Object o:切点方法属于的对象

package org.neuedu;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class MyAfterAdvice implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后置通知");
    }
}

Object o : 返回值对象

Method method : 切点方法对象

Object[] objects :切点方法参数

Object o1:切点方法属于的对象

7.3AspectJ方式配置AOP

上述配置还可以这样写

定义切面

package org.neuedu;

import org.aspectj.lang.ProceedingJoinPoint;

public class AdviceOfMine {
    public void beforeAdvice(){
        System.out.println("前置");
    }
    public void afterAdvice(){
        System.out.println("后置");
    }
    public void throwsAdvice(Exception e){
        System.out.println("异常信息:"+e.getMessage());
    }
    public Object arroundAdvice(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前置");
        Object proceed = point.proceed();// 放行
        System.out.println("环绕后置");
        return proceed;
    }
}
<?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
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="beforeAdvice" class="org.neuedu.AdviceOfMine"></bean>

    <aop:config>
        <aop:aspect ref="beforeAdvice">
            <aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>
            <!--前置通知-->
            <aop:before method="beforeAdvice" pointcut-ref="pointcut"></aop:before>
            <!--
                后置通知
                after-returning 不出异常才执行
                after 不管出不出异常都执行
            -->
            <aop:after method="afterAdvice" pointcut-ref="pointcut"></aop:after>
            <aop:after-returning method="afterAdvice" pointcut-ref="pointcut">
            </aop:after-returning>
            <!--异常通知-->
            <aop:after-throwing method="throwsAdvice" pointcut-ref="pointcut" throwing="e">
            </aop:after-throwing>
            <!--环绕通知-->
            <aop:around method="arroundAdvice" pointcut-ref="pointcut"></aop:around>
        </aop:aspect>
    </aop:config>

    <bean id="aopTest" class="org.neuedu.AOPTest"></bean>
</beans>
package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {
    public void test1() {
        System.out.println(1);
    }
    public void test2() {
        System.out.println(2);
    }
    public void test3() {
        System.out.println(3);
    }
    public static void main(String[] args) {
        // 使用aop,对象必须是spring管理的,所以这里不能new
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        AOPTest aopTest = applicationContext.getBean("aopTest", AOPTest.class);
        aopTest.test1();
        aopTest.test2();
        aopTest.test3();
    }
}

测试

####7.4.注解配置

注解是为了简化配置文件,但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: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
       https://www.springframework.org/schema/aop/spring-aop.xsd 			
       http://www.springframework.org/schema/context 
       https://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 启用注解扫描,如果多个包,用逗号分割 -->
    <context:component-scan base-package="org.neuedu.utils"></context:component-scan>
</beans>

先认识四个注解:这四个注解功能都一样,都是代替之前的bean标签,即只要在扫描包的类上加上这四个其中任意一个,该类就已经被Spring所管理了,但是可以从语义上明显感觉出来,后三个注解是在特定的包下使用的,

@Component 组件

@Service service

@Repository 仓库dao

@Controller 控制器

package org.neuedu.utils;
import org.springframework.stereotype.Component;

@Component
public class Test {}

相当于之前的

<bean id="test" class="org.neuedu.utils.Test"></bean>

注解给Test类默认起了id,为类名小写,即test,如果想自定义,可以这样写

package org.neuedu.utils;
import org.springframework.stereotype.Component;

@Component("test123")
public class Test {}
7.5利用注解配置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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.neuedu"></context:component-scan>
    <!--
        开启动态代理
        true 代表 cglib动态代理 注解都是基于 cglib做的
        false 代表 JDK动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

配置切点类

package org.neuedu;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
public class ComponentTest {
    @Pointcut("execution(* org.neuedu.ComponentTest.test())")
    public void test() {
        System.out.println("切点");
    }
}

配置切面类

package org.neuedu;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AdviceOfMine {
    @Before("org.neuedu.ComponentTest.test()")
    public void beforeAdvice(){
        System.out.println("前置");
    }
    @After("org.neuedu.ComponentTest.test()")
    public void afterAdvice(){
        System.out.println("后置");
    }
    @AfterThrowing(value = "org.neuedu.ComponentTest.test()",throwing = "e")
    public void throwsAdvice(Exception e){
        System.out.println("异常信息:"+e.getMessage());
    }
    @Around("org.neuedu.ComponentTest.test()")
    public Object arroundAdvice(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前置");
        Object proceed = point.proceed();// 放行
        System.out.println("环绕后置");
        return proceed;
    }
}

测试类

package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {
    public static void main(String[] args) {
        // 使用aop,对象必须是spring管理的,所以这里不能new
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        ComponentTest cTest = applicationContext.getBean("componentTest", ComponentTest.class);
        cTest.test();
    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8tQZJokJ-1573126039719)(/1570685075745.png)]

代理模式的核心作用就是通过代理,控制对对象的访问

如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP;如果目标对象没有实现了接口,则采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 动态代理之间转换。 (cglib和jdk动态代理区别,自行百度)

8.自动注入

package org.neuedu;
public class Warrior {
    private int level;
    private Weapon weapon;
}
package org.neuedu;

public class Weapon {}
<?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
       https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="warrior" class="org.neuedu.Warrior" autowire="byName"></bean>
    <bean id="weapon" class="org.neuedu.Weapon"></bean>
    
</beans>

autowire="byName" 通过名字自动注入

autowire="byType" 通过类型自动注入(多个时会出现矛盾)

9.Spring加载属性文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XcWIYfiV-1573126039720)(/1570708530514.png)]

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_yzn
jdbc.username=root
jdbc.password=root
<?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/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder location="classpath:db.properties">
    </context:property-placeholder>
    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--配置SessionFactory-->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置mapper扫描器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="factory"></property>
        <property name="basePackage" value="org.neuedu.mapper"></property>
    </bean>

    <bean id="userService" class="org.neuedu.service.UserService">
        <property name="userMapper" ref="userMapper"></property>
    </bean>
</beans>
9.1将属性文件中的属性注入到对象属性上
package org.neuedu;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class PropertyTest {
    // 这个类必须是Spring管理的才能注入
    @Value("${jdbc.driverClassName}")
    private String driver;
    public void show(){
        System.out.println(driver);
    }

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        PropertyTest test = applicationContext.getBean("propertyTest", PropertyTest.class);
        test.show();
    }
}

10.scope属性

scope默认值是singleton,也就是单例的,无论获取这个对象多少次都是一个对象

prototype 是多例

<bean id="warrior" class="org.neuedu.Warrior" autowire="byName" scope="singleton"></bean>
<bean id="warrior" class="org.neuedu.Warrior" autowire="byName" scope="prototype"></bean>

这里提醒下大家复习回顾下单例防止忘记

11.声明式事务

以前我们在JDBC中事务是由程序员编码自己控制的

声明式事务,程序员只需要声明哪些方法需要添加事务控制即可,而这些方法指的就是service层的方法

事务管理器是基于通知的,所以需要写通知

这里需要注意,IDEA给我们的约束中有一个是不对的,需要我自己修改成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1qD0nPa-1573126039722)(/1570711412980.png)]

<?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"
       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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx">
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--配置SessionFactory-->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置mapper扫描器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="factory"></property>
        <property name="basePackage" value="org.neuedu.mapper"></property>
    </bean>

    <!-- 声明式事务 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <tx:advice id="txAdivce" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="add*"/>
            <tx:method name="update*"/>
            <tx:method name="del*"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="myPointcut" expression="execution(* org.neuedu.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdivce" pointcut-ref="myPointcut"></aop:advisor>
    </aop:config>
</beans>
11.1事务传播行为(了解)

在事务管理的方法互相调用时发生传播行为,由propagation属性控制如何控制

<tx:attributes>
    <!-- "REQUIRED"默认值,有事务就在事务中执行,没有就开启一个事务,最常见 -->
    <tx:method name="add*" propagation="REQUIRED"/>
    <!-- "SUPPORTS"有事务就在事务中执行,没有就在无事务状态下执行 -->
    <tx:method name="update*" propagation="SUPPORTS"/>
    <!-- "MANDATORY"有事务就在当前事务中执行,否则就报错-->
    <!-- "REQUIRES_NEW"有事务就将其挂起,单独先执行自己的事务-->
    <!-- "NOT_SUPPORTED"必须在非事务下执行,没有事务正常执行,否则把当前事务挂起-->
    <!-- "Never"必须在非事务下执行,没有事务正常执行,否则抛异常-->
    <!-- "Nested"必须在事务下执行,没有事务新建事务,否则创建一个嵌套事务 -->
    <tx:method name="del*" propagation="MANDATORY"/>
    <tx:method name="*" read-only="true"/>
</tx:attributes>
11.2事务隔离级别(了解)

isolation属性 :在多线程或并发访问下如何保证访问到的数据具有完整性

脏读:事务a读取到事务b中未提交的数据,另一个事务数据可能改变了,此时A读取的数据与数据库不一致,此时读取的数据即为脏数据,这种读取到脏数据的现象称为脏读

不可重复读:事务a第一次读取数据,事务b对a读取的数据进行修改,事务a中再次读取的数据和之前读取不一致,主要发生在修改时(比如张三取钱时询问工作人员余额,得到反馈8万,此时张三老婆正在ATM取钱,取了5W,此时张三想取5W发现不够,两次读取结果不一样)

幻读:主要针对新增和删除,事务a按照特定条件查询,事务b新增了一条符合条件的数据,事务a查询的数据与数据库不一致,好像出现了幻觉,称为幻读

isolation属性主要解决的就是这些问题

取值可以是

default 数据库自己判断

read_uncommitted : 可以略去未提交的数据,可能出现脏读,不重复读,幻读,效率最高

read_committed : 只能读取其他事务中已提交的数据,防止脏读,可能出现不可重复读和幻读

repeatble_read : 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读,脏读,可能出现幻读

SERIALIZABLE : 排队操作,对整个表加锁,一个事务在操作时,另一个事务需要等待其完成才能操作,最安全,同时效率最低(银行项目一般对安全有要求)

11.3事务回滚(了解)
<tx:advice id="txAdivce" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception"/>
        <tx:method name="update*" propagation="SUPPORTS"/>
        <tx:method name="del*" propagation="NOT_SUPPORTED"/>
        <tx:method name="*" read-only="true"/>
    </tx:attributes>
</tx:advice>

在使用 throw 手动抛出异常时,建议加这个配置,否则不会回滚

<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception" no-rollback-for="java.lang.NullPointerException"/>

no-rollback-for 抛扫描异常时不会滚

12.常用注解

@Component

@Controller

@Service

@Repository

@Autowired spring提供的,默认按照byType注入

@Resource java提供的,默认按照byName注入,如果没有,按照byType注入

作用:自动按照类型完成依赖注入

@Value 获取properties中的值

@Pointcut 定义切点

@Aspect 定义切面

@Before 定义前置通知

@After 定义后置通知

@AfterReturing 定义返回通知

@Around 定义环绕通知

问到的数据具有完整性

脏读:事务a读取到事务b中未提交的数据,另一个事务数据可能改变了,此时A读取的数据与数据库不一致,此时读取的数据即为脏数据,这种读取到脏数据的现象称为脏读

不可重复读:事务a第一次读取数据,事务b对a读取的数据进行修改,事务a中再次读取的数据和之前读取不一致,主要发生在修改时(比如张三取钱时询问工作人员余额,得到反馈8万,此时张三老婆正在ATM取钱,取了5W,此时张三想取5W发现不够,两次读取结果不一样)

幻读:主要针对新增和删除,事务a按照特定条件查询,事务b新增了一条符合条件的数据,事务a查询的数据与数据库不一致,好像出现了幻觉,称为幻读

isolation属性主要解决的就是这些问题

取值可以是

default 数据库自己判断

read_uncommitted : 可以略去未提交的数据,可能出现脏读,不重复读,幻读,效率最高

read_committed : 只能读取其他事务中已提交的数据,防止脏读,可能出现不可重复读和幻读

repeatble_read : 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读,脏读,可能出现幻读

SERIALIZABLE : 排队操作,对整个表加锁,一个事务在操作时,另一个事务需要等待其完成才能操作,最安全,同时效率最低(银行项目一般对安全有要求)

11.3事务回滚(了解)
<tx:advice id="txAdivce" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception"/>
        <tx:method name="update*" propagation="SUPPORTS"/>
        <tx:method name="del*" propagation="NOT_SUPPORTED"/>
        <tx:method name="*" read-only="true"/>
    </tx:attributes>
</tx:advice>

在使用 throw 手动抛出异常时,建议加这个配置,否则不会回滚

<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception" no-rollback-for="java.lang.NullPointerException"/>

no-rollback-for 抛扫描异常时不会滚

12.常用注解

@Component

@Controller

@Service

@Repository

@Autowired spring提供的,默认按照byType注入

@Resource java提供的,默认按照byName注入,如果没有,按照byType注入

作用:自动按照类型完成依赖注入

@Value 获取properties中的值

@Pointcut 定义切点

@Aspect 定义切面

@Before 定义前置通知

@After 定义后置通知

@AfterReturing 定义返回通知

@Around 定义环绕通知

@AfterThrowing 定义异常通知

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值