Spring框架

Spring

本内容配套代码Gitee仓库链接:https://gitee.com/allureyu/spring_hx.git

第一章 Spring概述

1.Spring是轻量级的开源的J2EE框架
2.Spring可以解决企业应用开发的复杂性
3.Spring有两个核心部分:IOC和AOP
(1)IOC:控制反转,把创建对象的过程交给Spring容器进行管理
(2)AOP:面向切面,不修改原有代码进行功能增强
4.Spring框架的特点
(1)方便解耦,简化开发
(2)AOP编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事务的操作
(6)降低API的开发难度(封装了JDBC)

第二章 IOC容器

2.1 IOC的底层原理

  • 什么是IOC:
    控制反转:inversion of control
    把对象的创建和对象之间的调用都交给spring管理
    使用IOC的目的,为了降低耦合度
    入门案例就是IOC的实现

  • IOC的底层原理:
    底层技术:XML解析技术,设计模式,反射
    见图过程

在这里插入图片描述

2.2 IOC接口-BeanFactory

IOC思想基于IOC容器实现,IOC容器底层就是对象工厂
Spring提供IOC容器实现两种方式-两个接口

  • BeanFactory:

    • 概念:是IOC容器的基本实现,是Spring内部的接口,一般不提供给开发人员使用

    • 特点:在加载配置文件的时候,不会创建对象,在获取对象或者使用对象的时候才会创建

  • ApplicationContext:

    • 概念:是BeanFactory的子接口,提供了更多更强大的功能,一般开发人员使用
    • 特点:在加载配置文件的时候就会配置文件中的对象进行创建

2.3 IOC操作bean管理

什么是bean管理
1、bean管理指的是两个操作:Spring创建对象和Spring注入属性
2、Spring创建对象两种方式:基于xml配置文件和基于注解方式

第三章 XML方式操作bean

3.1 基于xml方式—创建对象

在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象的创建
bean标签中的常用属性:
id属性:唯一标识,表示给对象其标识或者别名
class属性:类的全路径(包类路径)
创建对象的时候,默认使用的是无参构造

<bean id="user" class="cn.diautowried.User"></bean>

3.2 基于xml方式—注入属性

DI:依赖注入,就是注入属性

  • 方式1:使用set方法进行属性注入

在spring配置文件中配置对象创建,配置属性注入
创建User对象,set方法进行属性注入:如下
property:表示属性的标签
name:表示实体类中的属性名
value:表示为属性名赋值

<?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">
    <!--xml方式配置bean,DI注入的两种方式-->
    <bean id="user" class="com.hx.pojo.User" scope="prototype">
        <!--DI注入:set注入,给对象的属性赋值-->
        <property name="name" value="tom"/>
        <property name="pwd" value="123"/>
    </bean>
</beans>
  • 方式2:使用有参构造进行属性注入

在spring配置文件中进行配置
使用有参构造注入属性:
constructor-arg:构造-参数
name:表示实体类中的属性名
value:表示为属性名赋值

<?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">
    <!--xml方式配置bean,DI注入的两种方式-->
    <bean id="user1" class="com.hx.pojo.User" scope="singleton">
        <!--DI注入:构造注入,给对象的属性赋值-->
        <constructor-arg name="name" value="Anny"/>
        <constructor-arg name="pwd" value="111"/>
    </bean>
</beans>

3.3 基于xml方式—注入外部bean属性

1 创建Dept和 Emp 对象
2 将Dept注入到Emp中
name属性值:类中的属性的名称
ref属性值:是Dept对象的bean标签的属性值

<?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-->
    <!--配置Emp的bean对象-->
    <bean id="emp1" class="com.hx.pojo.Emp">
        <property name="eno" value="1001"/>
        <property name="ename" value="乌拉"/>
        <property name="dept" ref="dept1"/>
    </bean>
    <!--外部bean:配置Dept的bean对象-->
    <bean id="dept1" class="com.hx.pojo.Dept">
        <property name="dno" value="10"/>
        <property name="dname" value="瓦格纳"/>
    </bean>
</beans>

3.4 基于xml方式—注入内部bean属性

1、创建Dept类 和 Emp类,建立一对多关系,
2、将Dept对象注入到Emp对象中

<?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-->
    <!--配置Emp的bean对象-->
    <bean id="emp1" class="com.hx.pojo.Emp">
        <property name="eno" value="1001"/>
        <property name="ename" value="乌拉"/>
        <!--内部bean-->
        <property name="dept">
            <bean id="dept1" class="com.hx.pojo.Dept">
                <property name="dno" value="20"/>
                <property name="dname" value="华约"/>
            </bean>
        </property>
    </bean>
</beans>

3.5 基于xml方式—注入集合属性

分别注入以下内容:
数组、List、Map、Set

设置实体类:Student

package com.hx.pojo;

import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Set;
@Data
public class Student {
    //设置属性
    //数组
    private String[] courses;
    //List集合
    public List<String> list;
    //Map集合
    private Map<String, String> map;
    //Set集合
    private Set<String> set;
    //课程的List集合
    private List<Course> courseList;
}

配置spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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-->
    <!--创建Student的bean-->
    <bean id="stu" class="com.hx.pojo.Student">
        <!--DI注入数组-->
        <property name="courses">
            <array>
                <value>语文</value>
                <value>数学</value>
                <value>外语</value>
            </array>
        </property>
        <!--DI注入List集合-->
        <property name="list">
            <list>
                <value>跳舞</value>
                <value>唱歌</value>
                <value>弹奏</value>
            </list>
        </property>
        <!--DI注入Map集合-->
        <property name="map">
            <map>
                <entry key="01" value="A"/>
                <entry key="02" value="B"/>
                <entry key="03" value="C"/>
            </map>
        </property>
        <!--DI注入Set集合-->
        <property name="set">
            <set>
                <value>篮球</value>
                <value>排球</value>
                <value>足球</value>
            </set>
        </property>
        <!--DI注入List中的Course-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
                <ref bean="course3"></ref>
            </list>
        </property>
    </bean>
    <!--创建课程Course的bean对象-->
    <bean id="course1" class="com.hx.pojo.Course">
        <property name="cno" value="101"/>
        <property name="cname" value="物理"/>
    </bean>
    <bean id="course2" class="com.hx.pojo.Course">
        <property name="cno" value="102"/>
        <property name="cname" value="化学"/>
    </bean>
    <bean id="course3" class="com.hx.pojo.Course">
        <property name="cno" value="103"/>
        <property name="cname" value="生物"/>
    </bean>
</beans>

3.6 基于xml方式—使用FactoryBean

1 Spring有两种类型的bean
       一种是普通bean
       一种是工厂bean,也就是FactoryBean
2 普通bean:在spring配置文件中定义bean的类型,返回类型就是此类型
   工厂bean:在spring配置文件中定义bean的类型,可以返回其他类
3、工厂bean案例
步骤1:创建类,设置这个类为工厂bean。实现接口FactoryBean
步骤2:实现接口中的方法,在此方法中定义返回的bean的类型

public class MyBean implements FactoryBean<Course> {

    //定义返回的bean对象是其他对象
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCourseName("社会与科学");
        return course;
    }

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

    @Override
    public boolean isSingleton() {
        return false;
    }
}
<bean id="myBean" class="cn.factorybean.MyBean"></bean>
测试bean的返回类型是其他类型--FactoryBean.
应该返回MyBean类型的对象,实际返回时Course类型对象

    @Test
    public void testMyBean(){
        //1、创建Spring的核心容器,并加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("spring4.xml");
        //2、获取对象
        Course course = context.getBean("myBean", Course.class);
        System.out.println(course);
    }

7 返回Course类型对象
在这里插入图片描述

3.7 基于xml方式—bean的作用域

在spring中,设置创建bean实例是单实例还是多实例
在默认情况下,spring容器创建的对象是单实例
如何设置单实例和多实例:
在spring配置文件中bean标签里有属性scope,用于设置单实例和多实例
第一个值:默认值singleton,表示的是单实例对象
第二个值:设置protoType。表示的是多实例对象

<!--测试作用域 单实例 和 多实例-->
<bean id="user1" class="cn.pojo.User" scope="singleton">
      <property name="username" value="张三"></property>
</bean>
<bean id="user2" class="cn.pojo.User" scope="prototype">
      <property name="username" value="张三"></property>
</bean>
  • singleton和protoType的区别:
    • singleton是单实例对象,设置scope的属性值是singleton,
      单实例对象会在spring配置文件加载的时候就创建
    • prototy是多实例对象,设置scope的属性值是prototype,
      不是在加载spring配置文件的时候创建对象,
      而是在调用getBean方法的时候创建多实例对象

3.8 基于xml方式—bean的生命周期

1、生命周期:从对象创建到对象销毁的过程
2、bean的生命周期—简化五步
(1)、通过构造器创建bean实例,也就是执行无参构造
(2)、为bean的属性设置值,以及对其他bean的调用(调用set方法)
(3)、调用bean的初始化方法,(初始化的方法需要进行配置)
(4)、bean可以使用,对象可以获取
(5)、当容器在关闭的时候,会调用bean的销毁方法(销毁的方法需要进行配置)

  • 案例
package com.hx.pojo;
/*
    bean的生命周期
 */
public class Phone {
    //设置成员属性
    private String brand;
    //1、实例化bean
    public Phone() {
        System.out.println("第一步:调用无参构造,实例化bean");
    }
    //2、给bean的属性赋值
    public void setBrand(String brand) {
        this.brand = brand;
        System.out.println("第二步:给bean的属性赋值");
    }
    //3、执行bean的初始化操作
    public void initBean(){
        System.out.println("第三步:执行bean的初始化操作");
    }
    //4、调用bean的方法
    public void call(){
        System.out.println("第四步:调用bean的方法正常工作");
    }
    //5、销毁bean
    public void destoryBean(){
        System.out.println("第五步:销毁bean");
    }
}
在配置spring.xml文件中配置如下信息:
	init-method="initBean" :配置初始化方法
	destroy-method="destoryBean" :配置销毁方法
<bean id="phone" class="com.hx.pojo.Phone" init-method="initBean" destroy-method="destoryBean">
    <property name="brand" value="华为"/>
</bean>
  • 测试
    @Test
    public void m6(){
        //1、获取IOC控制反转容器
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring06.xml");
        //2、通过容器获取对象
        Phone phone = context.getBean("phone", Phone.class);
        //3、调用bean的方法
        phone.call();
        //4、关闭IOC容器
        context.close();
    }
  • 结果

在这里插入图片描述

3.9 基于xml方式—自动装配

1、什么是自动装配?什么是手动装配

  • 手动装配:
    是程序员在配置文件中手动的进行属性的赋值,即value属性值和ref属性值
  • 自动装配:
    根据指定的装配规则,根据属性名称或者属性类型,Spring自动将匹配的属性值进行注入

2 案例

  • 将Dept的对象注入到Emp中
    在这里插入图片描述

  • spring.xml配置根据名称和根据类型注入

    • 自动装配根据名称注入:保证注入的bean的id名和实体类中的属性名保持一致。如果不一致,注入失败
    • 自动装配根据类型注入: 只能有一个该类型的bean对象,不能出现多个,不然容器不知道选择哪一个bean对象进行注入操作
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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名和实体类中的属性名保持一致
                如果不一致,注入失败
    -->
    <bean id="emp" class="com.hx.pojo.Emp" autowire="byName">
        <property name="eno" value="1001"/>
        <property name="ename" value="刘能"/>
    </bean>
    <bean id="dept" class="com.hx.pojo.Dept">
        <property name="dno" value="10"/>
        <property name="dname" value="人事部"/>
    </bean>

    <!--自动装备方式二:根据类型注入
        注意点:根据类型进行自动装配,只能有一个该类型的bean对象
                不能出现多个,不然容器不知道选择哪一个bean对象进行注入操作
    -->
    <bean id="emp1" class="com.hx.pojo.Emp" autowire="byType">
        <property name="eno" value="1002"/>
        <property name="ename" value="赵四"/>
    </bean>
</beans>
  • 测试
    @Test
    public void m7(){
        //1、获取IOC控制反转容器
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring07.xml");
        //2、通过容器获取对象
        Emp emp = context.getBean("emp", Emp.class);
        System.out.println(emp);
    }

    @Test
    public void m8(){
        //1、获取IOC控制反转容器
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring07.xml");
        //2、通过容器获取对象
        Emp emp = context.getBean("emp1", Emp.class);
        System.out.println(emp);
    }

第四章 注解方式操作bean

4.1 常用创建bean对象的注解

1、什么是注解
注解是代码的特殊标记:
格式:@注解名(属性名=属性值,属性名=属性值)
使用注解:注解作用在类上面,方法上面,属性上面
使用注解的目的:简化xml设置

2、Spring针对Bean管理中创建对象提供注解
@Component:笔试普通的bean
@Service:表示业务层
@Controller:表示控制层
@Repository:表示持久层

以上四个注解功能是一样的,都可以用来创建bean实例。注解中的value值可以自定义,相当于bean标签中的id属性值。value值可以省略不写,默认值是类名称的首字母小写

4.2 基于注解方式–实现对象创建

1 创建类,在类上添加创建对象的注解

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

2 配置spring.xml

  • 1 开启组件扫描:
    1、如果扫描多个包,多个包之间使用逗号隔开
    2、扫描包的上层目录
<context:component-scan base-package="cn.anno"></context:component-scan>
  • 2 设置组件扫描-设置包含哪些注解
    use-default-filters=“false” : 表示不使用默认的filter,自行配置filter
    context:include-filter : 设置扫描哪些内容
    属性:type:annotation
    属性:expression:只扫描对应表达式的注解
<context:component-scan base-package="cn.anno" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
  • 3 设置组件扫描-设置排除哪些注解
    默认扫描所有注解,可以排除execlude扫描指定注解
    context:exclude-filter :设置不扫描哪些内容
    属性:type:annotation
    属性:expression:不扫描对应表达式的注解
<context:component-scan base-package="cn.anno">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

3、完整的配置文件(主要添加context约束)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描,扫描的是类上面Spring的注解-->
    <context:component-scan base-package="com.hx">
        <!--过滤指定的注解可以创建bean对象-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <!--排除指定的注解不允许创建bean对象-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

4.3 基于注解方式–实现属性注入

  • 1、@AutoWired :根据属性类型进行注入

@AutoWired :根据属性类型进行注入、按照类型(byType)装配依赖对象,
1、使用@Autowired,默认required = true。即表示被注入bean对象可以被实例化的
2、如果被注入的bean对象不能被实例化,即为null。需要设置@Autowired的required = false

  • 2、@AutoWired:根据属性名称进行注入

1、在@AutoWired注解通过类型注入的前提下:如果被注入的接口有多个实现类对象,那么就可以按照名称(byName)来装配,可以结合@Qualifier 注解一起使用。

2、如果不使用@Qualifier注解进行value属性的标识,那么容器会为此接口的多个实现类创建bean对象。此时,容器不知道改注入哪个实现类的bean对象,会报如下异常

NoUniqueBeanDefinitionException:
No qualifying bean of type 'cn.anno.dao.UserDao'available: 
expected single matching bean but found 3:userDaoImpl1,userDaoImpl2,userDaoImpl3

在这里插入图片描述

  • .3、@Resource: 可以根据类型注入,可以根据名称注入

@Resource: 可以根据类型注入,可以根据名称注入
@Resource不是spring的注解,而是javax的注解。
@Resource默认按照byName自动注入
@Resource 有两个重要的属性:name和type
Spring将@Resource注解的:name属性解析为bean的名字,type属性则解析为bean的类型。
如果使用 name 属性,则使用 byName 的自动注入策略,
如果使用 type 属性时则使用 byType 自动注入策略。
如果既不制定 name 也不制定 type 属性,这时将通过反射机制使用 byName 自动注入策略。

在这里插入图片描述在这里插入图片描述

  • 4、@Value 注入普通类型属性

@Value注解:
注入普通类型属性,为普通属性赋值。属性value的值,会赋值给name
@Value(value = “Tom”)
private String name;

4.4 基于注解方式–实现完全注解开发

创建SpringConfig配置类,替代spring.xml文件
@Configuration:注解:表示标识此类是配置类
@ComponentScan(“cn.spring”)注解:表示开启注解扫描。括号中的值,表示开启扫描此包下的所有注解

@Configuration//作为配置类。替代xml核心配置文件
@ComponentScan("cn.spring")
public class SpringConfig {}
	@Test
    public void test1(){
        //1、创建核心容器,加载配置类
        AnnotationConfigApplicationContext ccontex =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //2、通过容器获取bean对象
        UserService userService = ccontex.getBean("userService", UserService.class);
        //3、调用方法
        userService.add();
        System.out.println(userService);
    }

第五章 面向切面编程AOP

5.1 AOP概念

官方:面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率
通俗:不修改源代码的方式,在主干功能里添加新的功能

在这里插入图片描述

5.2 AOP原理

1、AOP底层使用动态代理,有两种情况的动态代理

第一种:有接口情况–使用JDK动态代理。创建接口实现类的代理对象,增强类的方法
第二种:没有接口情况–使用CGLIB动态代理。创建子类的代理对象,增强类的方法

JDK动态代理在这里插入图片描述
CGLIB动态代理
在这里插入图片描述

2 JDK动态代理和CGLIB动态代理的区别

  • 1、概念:
    JDK代理:使用的是反射机制生成一个实现代理接口的匿名类,
    在调用具体方法前调用InvokeHandler来处理。
    CGLIB代理:使用字节码处理框架asm,
    对代理对象类的class文件加载进来,
    通过修改字节码生成子类。

  • 2、效率:
    JDK创建代理对象效率较高,执行效率较低;
    CGLIB创建代理对象效率较低,执行效率高。

  • 3、关系:
    JDK动态代理机制是委托机制,只能对实现接口的类生成代理,
    通过反射动态实现接口类;
    CGLIB则使用的继承机制,针对类实现代理,
    被代理类和代理类是继承关系,
    所以代理类是可以赋值给被代理类的,
    因为是继承机制,不能代理final修饰的类。

  • 4、实现:
    JDK代理是不需要依赖第三方的库,只要JDK环境就可以进行代理,需要满足以下要求:
    1.实现InvocationHandler接口,重写invoke()
    2.使用Proxy.newProxyInstance()产生代理对象
    3.被代理的对象必须要实现接口
    CGLIB 必须依赖于CGLIB的类库,需要满足以下要求:
    1.实现MethodInterceptor接口,重写intercept()
    2.使用Enhancer对象.create()产生代理对象

  • 5、使用场景:
    1)如果目标对象实现了接口,
    默认情况下会采用JDK的动态代理实现AOP,
    可以强制使用CGLIB实现AOP
    2)如果目标对象没有实现了接口,
    必须采用CGLIB库,
    spring会自动在JDK动态代理和CGLIB之间转换

5.3 AOP相关术语

  • 连接点:类里面的那些方法可以增强,这些方法就被成为连接点
  • 切入点:实际被增强的方法,称为切入点
  • 通知(增强):实际增强的逻辑部分,被称为通知,有五种类型的通知
  • 切面:把通知应用到切入点的过程,就是切面
通知类型执行点
前置通知在目标方法执行之前执行
后置通知在目标方法执行之后执行
环绕通知在目标方法执行之前后执行
异常通知在目标方法发生异常时执行
返回通知在目标方法执行返回值时执行

在这里插入图片描述

5.4 AOP操作准备

  • 1、Spring和AspectJ的关系

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

  • 2、引入AOP依赖
	 <!--spring-AOP依赖-->
    <dependency>
      		<groupId>org.springframework</groupId>
      		<artifactId>spring-aop</artifactId>
      		<version>5.2.5.RELEASE</version>
    </dependency>
           
    <!--Aspect切面依赖-->
    <dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>        
			<version>1.9.9.1</version>
	</dependency>

    <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
		  <version>1.9.9.1</version>
	</dependency>
  • 3、切入点表达式

切入点表达式的作用:知道对哪个类里面的哪个方法进行增强
切入点表达式语法:

 	 execution([权限修饰符][返回类型][类的路径][方法名称][参数列表])
       举例1:对cn.aop.hx包中的UserDao类里面的add方法做增强
             execution(* cn.aop.hx.UserDao.add(..))
       举例2:对cn.aop.hx包中的UserDao类里面的所有方法做增强
             execution(* cn.aop.hx.UserDao. * (..))
       举例3:对cn.aop.hx包中的所有类,以及里面的所有方法做增强
             execution(* cn.aop.hx. * . * (..))

5.5 基于@Aspect注解的操作AOP

  • 1、创建目标类
package com.hx.strong;

import org.springframework.stereotype.Service;

//目标类
@Service
public class UserServiceImpl {
    //定义成员方法---目标方法
    public String checkData(){
        System.out.println("我是目标方法,即切入点!");
        String s = new String("检查通过!");
        return s;
    }

    public void add(){
        System.out.println("目标方法发生异常!");
        int i = 1/0;
    }
}

  • 2、创建切面类–通知所在的类
package com.hx.strong;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//可以被组件扫描
@Component
//表示此类是切面类
@Aspect
//开启生成代理对象的配置
@EnableAspectJAutoProxy
@Order(value = 2)
public class UserServiceAspect1 {

    //提取相同的切入点表达式
    //承载方法
    @Pointcut(value = "execution(* com.hx.strong.UserServiceImpl.checkData(..))")
    public void pointCut(){

    }

    //后置通知 After 细粒度:扫描指定包类下的所有方法
    @After(value = "pointCut()")
    public void after(){
        System.out.println("后置通知:在目标方法执行之后执行");
    }

    //返回通知 AfterReturning
    @AfterReturning( value = "pointCut()")
    public void AfterReturning(){
        System.out.println("返回通知:在目标方法返回结果前时执行");
    }

    //异常通知 AfterThrowing
    @AfterThrowing(value = "execution(* com.hx.strong.UserServiceImpl.add(..))")
    public void  afterThrowing(){
        System.out.println("异常通知:在目标方法执行出现异常时执行!");
    }

    //环绕通知 Around
    @Around(value = "pointCut()")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        //pj:封装了目标方法
        //执行前增强功能
        System.out.println("环绕通知前:目标方法执行前增强功能");
        //目标方法执行
        Object result = jp.proceed();
        System.out.println(result);
        //执行后增强功能
        System.out.println("环绕通知后:目标方法执行后增强功能");
    }
}
package com.hx.strong;

import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//可以被组件扫描
@Component
//表示此类是切面类
@Aspect
//开启生成代理对象的配置
@EnableAspectJAutoProxy
@Order(value = 1)
public class UserServiceAspect2 {

    //提取相同的切入点表达式
    //承载方法
    @Pointcut(value = "execution(* com.hx.strong.UserServiceImpl.checkData(..))")
    public void pointCut(){

    }

    //前置通知 Before  细粒度:准确定位指定包类下的方法
    @Before(value = "pointCut()")
    public void before(){
        System.out.println("前置通知:在目标方法执行之前执行");
    }
}

  • 3、创建配置类
package com.hx.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/*
    配置类
 */
@ComponentScan(basePackages = "com.hx")
@Configuration
public class SpringConfig {

}
  • 4、测试操作
import com.hx.config.SpringConfig;
import com.hx.strong.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestAOP {
    @Test
    public void m1() {
        //1、创建容器,加载核心配置类
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //2、创建bean对象
        UserServiceImpl userServiceImpl = context.getBean(UserServiceImpl.class);
        //3、调用方法
        userServiceImpl.checkData();
    }

    @Test
    public void m2() {
        //1、创建容器,加载核心配置类
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //2、创建bean对象
        UserServiceImpl userServiceImpl = context.getBean(UserServiceImpl.class);
        //3、调用方法
        userServiceImpl.add();
    }

    /*
    默认的通知优先级
        环绕通知前:目标方法执行前增强功能
        前置通知:在目标方法执行之前执行
        我是目标方法,即切入点!
        检查通过!
        环绕通知后:目标方法执行后增强功能
        后置通知:在目标方法执行之后执行
        返回通知:在目标方法返回结果前时执行
     */
}
  • 5、测试结果

目标方法无异常时,通知的执行顺序:
around 前。。。目标方法执行之前执行
before。。。在目标方法执行之前执行
我是目标方法,也就是被增强的方法。。。。我执行了
around 后。。目标方法执行之后执行
after。。。在目标方法执行之后执行
afterReturning。。。在目标方法执行返回之后执行

目标方法发生异常时,通知的执行顺序:
around 前。。。目标方法执行之前执行
before。。。在目标方法执行之前执行
after。。。在目标方法执行之后执行
afterThrowing。。。在目标方法执行发生异常执行

  • 6、相同切入点提取
    //提取相同的切入点表达式
    //承载方法
    @Pointcut(value = "execution(* com.hx.strong.UserServiceImpl.checkData(..))")
    public void pointCut(){

    }
  • 7、切面优先级的设置
@Order(value = 1)

设置增强的优先级(同一个目标方法有多个切面增强的情况)
在增强类上面添加注解@Order(数字类型值),数字类型值越小,优先级越高

第六章 JdbcTemplate

6.1 JdbcTemplate—介绍

spring框架对JDBC进行封装,
使用JDBCTemplate方便实现对数据库操作

6.2 JdbcTemplate—依赖

  • 1 引入JDBCTemplate和事务的依赖
        <!--   日志     -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!--   spring的核心上下文     -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>

        <!--   spring测试     -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.17</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>

        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

        <!--事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <!--spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
  • 2、配置数据源和JDBCTemplate

方式1:xml方式
在spring.xml配置文件中配置数据库连接池

<!--配置德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="clone">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql:///user_db"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

配置JDBCTemplate对象,为其注入DataSource

<!--配置JDBCTemplate 查看源码-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
     <!--注入DataSource-->
     <property name="dataSource" ref="dataSource"></property>
</bean>

方式2:配置类方式

package com.hx.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

//标识此类是配置类
@Configuration
public class JdbcTemplateConfig {

    //IOC容器实例化DruidDataSource的bean对象
    @Bean
    public DruidDataSource getDruidDataSource(){
        //创建连接池对象
        DruidDataSource dataSource = new DruidDataSource();
        //设置数据库驱动
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        //设置数据库连接地址
        dataSource.setUrl("jdbc:mysql:///user_db");
        //设置数据库用户名
        dataSource.setUsername("root");
        //设置数据库密码
        dataSource.setPassword("root");
        //返回数据库连接池对象
        return dataSource;
    }

    //IOC容器实例化JdbcTemplate的bean对象
    @Bean
    public JdbcTemplate getJdbcTemplate(){
        //创建JdbcTemplate对象
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //设置数据源属性
        jdbcTemplate.setDataSource(getDruidDataSource());
        //返回对象
        return jdbcTemplate;
    }
}

6.3 JdbcTemplate—新增

API方法:
update方法用于增删改的操作
update(String sql,Object[]… args)
有两个参数:
第一个参数:sql语句
第二个参数:可变参数,设置sql语句的值

@Repository
public class UserDaoImpl implements UserDao {

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //添加的方法
    @Override
    public void add(User user) {
        //编写SQL语句
        String sql1 = "insert into t_user values(null ,?,?)";
        //获取参数值
        Object[] args = {user.getUserName(), user.getUserStatus()};
        //进行新增操作,返回操作数
        int update = jdbcTemplate.update(sql1,args);
        //输出行记录
        System.out.println(update);
    }
}

6.4 JdbcTemplate—修改和删除

API方法:
update方法用于增删改的操作
update(String sql,Object[]… args)
有两个参数:
第一个参数:sql语句
第二个参数:可变参数,设置sql语句的值

@Repository
public class UserDaoImpl implements UserDao {

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
 	//修改的方法
    @Override
    public void update(User user) {
        //注意:sql语句中的字段名称要与数据库表中的字段名称一致
        String sql2 = "update t_user set user_name=?,user_status=? where user_id=?";
        Object[] args = {user.getUserName(), user.getUserStatus(),user.getUserId()};
        int update = jdbcTemplate.update(sql2,args);
        System.out.println(update);
    }

    //删除的方法
    @Override
    public void delete(Integer id) {
        String sql3 = "delete from t_user where user_id=?";
        int update = jdbcTemplate.update(sql3,id);
        System.out.println(update);
    }
}

6.5 JdbcTemplate—查询

1 查询返回某个值—查询所有记录总数

API方法:
jdbcTemplate.queryForObject(String sql, Class requiredType)
此方法有连个参数:
第一个参数:sql语句
第二个参数:返回类型Class

 //查询所有记录
    @Override
    public int getAll() {
        //编写sql语句
        String sql4 = "select count(*) from t_user";
        //执行查询操作,第一个参数是sql。第二个参数是返回值的类型class
        Integer count =  jdbcTemplate.queryForObject(sql4, Integer.class);
        //返回结果
        return count;
    }

2 查询返回某对象

API方法:
jdbcTemplate.queryForObject(String sql, RowMapper rowMapper ,Object… args )
此方法有三个参数:
第一个参数:sql语句
第二个参数:RowMapper是接口,可以返回不同类型的数据,使用接口中的实现类,可以完成数据的封装
第三个参数:传递sql语句中问号的值

    //通过id查询
    @Override
    public User selectUserById(Integer id) {
        //编写sql
        String sql5 = "select * from t_user where user_id=?";
        //执行查询操作
        /*
            jdbcTemplate.queryForObject(String sql, RowMapper<T> rowMapper ,Object... args )
            第一个参数:sql语句
            第二个参数:RowMapper是接口,可以返回不同类型的数据,使用接口中的实现类,可以完成数据的封装
            第三个参数:传递sql语句中问号的值
         */
        User user = 
        	jdbcTemplate.queryForObject(sql5, new BeanPropertyRowMapper<User>(User.class), id);
        return user;
    }

3 查询返回某集合

API方法:
jdbcTemplate.query(String sql, RowMapper rowMapper ,Object… args )
此方法有三个参数:
第一个参数:sql语句
第二个参数:RowMapper是接口,可以返回不同类型的数据,使用接口中的实现类,可以完成数据的封装
第三个参数:传递sql语句中问号的值

//返回集合数据
    @Override
    public List<User> findAllUser() {
        //编写sql
        String sql6 = "select * from t_user";
        //执行查询操作
        List<User> userList = jdbcTemplate.query(sql6, new BeanPropertyRowMapper<User>(User.class));
        return userList;
    }

4 批量操作—新增

API方法:
batchUpdate(String sql,List<Object[]> batchArgs)
两个参数:
第一个参数:sql语句
第二个参数:list集合,添加多条记录数据

//批量添加
    @Override
    public void batchAddUser(List<Object[]> batchArgs) {
        String sql7 = "insert into t_user values(null,?,?)";
        int[] ints = jdbcTemplate.batchUpdate(sql7,batchArgs);
        System.out.println(Arrays.toString(ints));
    }

5 批量操作—修改和删除

API方法:
batchUpdate(String sql,List<Object[]> batchArgs)
两个参数:
第一个参数:sql语句
第二个参数:list集合,添加多条记录数据

    //批量修改
    @Override
    public void batchUpdateUser(List<Object[]> batchArgs) {
        String sql8 = "update t_user set user_name=?,user_status=? where user_id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql8,batchArgs);
        System.out.println(Arrays.toString(ints));
    }
    
    //批量删除
    @Override
    public void batchDelete(List<Object[]> batchArgs) {
        String sql9 = "delete from t_user where user_id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql9,batchArgs);
        System.out.println(Arrays.toString(ints));
    }

第七章 事务

7.1 事务的概念

事务是数据库操作的最基本的单元,是逻辑上的一组操作,要么都成功,如果有一个失败,所有操作都失败。典型案例银行转账

典型场景:
lucy转账100给mary。lucy少100,mary多100
执行成功:lucy少了100 , mary多了100, 表示的是逻辑上的一组操作
执行失败:转账的过程中出点断电,断网导致异常,那么lucy的钱不会少,mary的钱也不会多

7.2 事务的特性

特性含义
原子性原子性意味着数据库中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行
一致性一致性即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏
隔离性事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据
持久性意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

7.3 事务的管理

1、事务一般添加到JavaEE三层架构里的Service层,也就是业务逻辑层
2、在Spring中进行事务管理,提供了两种方式,即编式事务和声明式事务。编程时事务:不建议使用,代码臃肿,不易维护。而声明式事务:使用方便
3、声明式事务:
可以基于注解方式实现事务管理,也可以基于xml配置文件方式
在Spring进行声明式事务管理。底层用到了AOP原理,提供可一个接口,代表事务管理器,这个接口针对不同的框架提供了不同的实现类

7.4 事务的隔离级别

1、事务问题
在多事务操作之间如果不考虑隔离会产生很多问题,如下:

脏读一个未提交的事务读取到了另一个未提交事务的数据
幻读一个事务读取到另一个提交事务的添加数据
不可重复读一个未提交的事务读取到了另一个已提交事务修改的数据

2、解决方案:
通过设置事务隔离级别,解决读的问题
在这里插入图片描述

7.5 基于注解方式的声明式事务

  • 1、创建Module,引入依赖
<dependencies>
        <!--spring的核心上下文-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>

        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

        <!--事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <!--spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        
        <!--连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
    </dependencies>
  • 2、创建配置类代替核心配置文件
@Configuration
@ComponentScan(basePackages = "com.hx")
public class SpringConfig {

    //获取数据源对象
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybase?ServerTimeZone = UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    //获取JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(getDruidDataSource());
        return jdbcTemplate;
    }
}
  • 3、创建数据库表 account
    在这里插入图片描述
  • 4、创建接口UserDao,并提供方法
public interface UserDao {
    //多钱的方法
    void addMoney();

    //少钱的方法
    void reduceMoney();
}
  • 5、创建类UserService类,并注入UserDao
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    //转账的方法
    public void accountMoney(){
        //lucy少100
        userDao.reduceMoney();
        //mary多100
        userDao.addMoney();
    }
}
  • 6、创建实现类UserDaoImpl
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //少钱操作:lucy转钱给mary100
    @Override
    public void reduceMoney() {
        String sql = "update account set money = money-? where name = ?";
        jdbcTemplate.update(sql, 100, "lucy");
    }

    //多钱操作:mary收到转账100
    @Override
    public void addMoney() {
        String sql = "update account set money = money+? where name = ?";
        jdbcTemplate.update(sql, 100, "mary");
    }
}
  • 7、编写测试类执行转账操作
public class TestAccount {
    @Test
    public void test1(){
        //创建容器对象
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取bean对象
        UserService userService = context.getBean(UserService.class);
        //调用方法
        userService.accountMoney();
    }
}
  • 8、查看结果
    转账成功,lucy少100,mary多100
    在这里插入图片描述

  • 9、当程序发生异常(手动设置异常)
    在这里插入图片描述

  • 10 、再次测试,发生异常,查看数据库结果
    看数据库变化-----不符合逻辑
    其中:mary的money没有改变
    但是,lucy的money的钱少了100
    在这里插入图片描述在这里插入图片描述

  • 11、解决方案—添加事务

  • 12、在配置类SpringConfig中创建事务管理器bean对象,

在配置类SpringConfig中创建事务管理器bean对象
并在配置类上添加注解@EnableTransactionManagement,用于开启事务管理

@Configuration//配置类
@ComponentScan(basePackages = "com.hx")//注解扫描
@EnableTransactionManagement//开启事务
public class SpringConfig {

    //创建DruidDataSource对象
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql:///mybase");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }

    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DruidDataSource druidDataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //在IOC容器中根据数据类型,找到DruidDataSource,并注入
        jdbcTemplate.setDataSource(druidDataSource);
        return jdbcTemplate;
    }

    //创建事务管理器DataSourceTransactionManager对象
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource druidDataSource){
        DataSourceTransactionManager dataSourceTransactionManager =
                new DataSourceTransactionManager();
        //在IOC容器中根据数据类型,找到DruidDataSource,并注入
        dataSourceTransactionManager.setDataSource(druidDataSource);
        return dataSourceTransactionManager;
    }
}
  • 13、在service类上面添加注解@Transactional
    @Tranasctional注解是Spring 框架提供的声明式注解事务解决方案,在开发中使用事务保证方法对数据库操作的原子性,要么全部成功,要么全部失败.

在这里插入图片描述

  • 14、再次测试,查看数据库结果
    发生异常,数据不发生变化,执行事务的回滚操作。
    在这里插入图片描述

7.6 @Transactional

1 @Transactional概念
@Tranasctional注解是Spring 框架提供的声明式注解事务解决方案,在开发中使用事务保证方法对数据库操作的原子性,要么全部成功,要么全部失败。

2 @Transactional作用范围

作用范围含义
作用于类当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息
作用于方法当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息
作用于接口不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效

3 @Transactional 注解的属性

public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}
  • 1、事务的传播行为—propagation属性
    代表事务的传播行为,共有七种。默认值为 Propagation.REQUIRED
传播行为含义
Propagation.REQUIRED如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务
Propagation.SUPPORTS如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行
Propagation.MANDATORY如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常
Propagation.REQUIRES_NEW重新创建一个新的事务,如果当前存在事务,暂停当前的事务
Propagation.NOT_SUPPORTED以非事务的方式运行,如果当前存在事务,暂停当前的事务
Propagation.NEVER以非事务的方式运行,如果当前存在事务,则抛出异常
Propagation.NESTED和 Propagation.REQUIRED 效果一样
  • 2 事务的隔离界别–isolation 属性
    isolation :事务的隔离级别,默认值为 Isolation.DEFAULT
隔离级别含义
Isolation.DEFAULT使用底层数据库默认的隔离级别
Isolation.READ_UNCOMMITTED读未提交
Isolation.READ_COMMITTED读已提交
Isolation.REPEATABLE_READ可重复读
Isolation.SERIALIZABLE序列化
  • 3 timeout 属性
    timeout :事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。

  • 4 readOnly 属性
    readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。

  • 5 rollbackFor 属性
    rollbackFor :用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。

  • 6 noRollbackFor属性
    noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值