学习资料:Spring官方文档
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。

一.IOC

当我们自己写一个简易的程序的时候,我们总会要new很多对象,但如果要写一个大项目呢,多个类之间互相耦合,关系复杂,不宜处理。这个时候,有人就想到了,搞一个容器,它负责所有的类的生成、注入、装配,来解除耦合,这就是IOC容器。

通俗来讲,就是将new实例这个过程,放到spring(IOC)容器里来做。当项目初始化的时候,spring(IOC)容器会先实例化要所有使用的类,然后需要用到这个实例的时候,从spring(IOC)容器中将这个实例注入即可。那么怎么告诉spring哪些类要实例化、怎么实例化呢?Spring可以通过xml或者注解获取这些信息。

二.XML注入

1.set注入

要求:有无参构造和set方法
解释:就是通过调用set方法,将对应的属性注入,可以直接注入值(property),也可以注入bean的引用(ref)或者一些集合。
样例:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="address" class="com.pojo.Address"><property name="address" value="xian"></property></bean><bean id="student" class="com.pojo.Student"><property name="name" value="hou"/><property name="address" ref="address"/><!--数组注入--><property name="books"><array><value>三国</value><value>西游</value><value>水浒</value></array></property><!--list--><property name="hobbies"><list><value>eat</value><value>drink</value><value>play</value></list></property><property name="card"><map><entry key="1" value="12"/><entry key="2" value="23"/></map></property><property name="game"><set><value>wangzhe</value><value>daota</value><value>lol</value></set></property><property name="wife"><null></null></property><!--properties--><property name="infor"><props><prop key="id">20200405</prop><prop key="name">hdk</prop></props></property></bean></beans>

补充:bean中可以补充name设置别名(分隔符可以用逗号,空格或者分号),也可以直接设置别名

<bean id="usert" class="com.hou.pojo.UsetT" name="u1,u2"><property name="name" value="kun"/>
</bean><alias name="user" alias="user2aaa"/>

2.构造器注入

要求:有一个或多个有参构造
解释:就是通过spring的有参构造(constructor-arg),将对应的属性注入
样例:

<bean id="user" class="com.hou.pojo.User"><constructor-arg name="name" value="hou"></constructor-arg>
</bean>

3.p和c注入

要求:p的命名空间以及set注入要求 c的命名空间以及构造器注入要求
解释:p注入就是对set注入的一个简化封装,c注入就是对构造器注入的简化封装
可以直接通过"p:属性名"或者"c:属性名"的方式直接在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"xmlns:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--p命名空间注入/set注入--><bean id="use" class="com.pojo.User" p:name="dong" p:age="10"></bean><!--c命名空间/构造器--><bean id="use2" class="com.pojo.User" c:name="kun" c:age="19" scope="prototype"></bean>
</beans>

补充:scope作用域
scope是bean里的一个属性,可以指定使用单例模式还是原型模式或者web中的session、request、application、websocket
单例就是只使用一个实例,原型就是每次注入的时候都new一个新的实例,默认是单例
也可以通过注解@scope实现

三.自动装配

将一个复杂的类的配置进行简化。
可以使用bean的autowire属性,以byName或者byType的方式进行装配。
但用注释进行装配会更加简单,这里只介绍注释自动装配。
@Autowired注释会先根据类型进行注入,如果有多个满足的类型,再根据name进行注入

注解装配条件:

  1. jdk1.5+
  2. spring2.5+
  3. context上下文:
    xmlns:context=“http://www.springframework.org/schema/context”
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
  4. spring-aop包
  5. @Autowired注释

<context:annotation-config/>可以让已经注册过的bean注册以下四种Processor,也就是可以使用以下四种Processor对应的注解。

  1. AutowiredAnnotationBeanPostProcessor
  2. CommonAnnotationBeanPostProcessor
  3. PersistenceAnnotationBeanPostProcessor
  4. RequiredAnnotationBeanPostProcessor

例子:

<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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/><bean id="cat111" class="com.pojo.Cat"/><bean id="dog" class="com.pojo.Dog"/><bean id="people" class="com.pojo.People"></bean></beans>
public class People {@Autowiredprivate Cat cat;@Autowired@Qualifier(value = "dog")private Dog dog;private String name;@Overridepublic String toString() {return "People{" +"cat=" + cat +", dog=" + dog +", name='" + name + '\'' +'}';}public Cat getCat() {return cat;}public void setCat(Cat cat) {this.cat = cat;}public Dog getDog() {return dog;}public void setDog(Dog dog) {this.dog = dog;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

补充:
@Nullable:代表对象可以为null,放在类型前面
@Autowired(required=false):代表@Nullable
@Qualifier(value=""):当@Autowired环境很复杂时,手动指定装配的实例名称,配合@Autowired使用
@Resource:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

四.注解开发

约束:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--指定要扫描的包--><context:component-scan base-package="com.pojo"/></beans>

<context:component-scan base-package="com.pojo"/>可以通过注解去注册bean,并包含了<context:annotation-config/>的所有功能!
按照不同的指责可以使用 组件@Component,控制器@Controller,DAO@Repository,服务@Service,代表这个类被Spring管理;
用@Value("")来对属性进行赋值,可以放在set方法或者属性上面。

package com.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;//等价于<bean id="user" class="com.pojo.User"></bean>
@Component
@Scope("prototype")
public class User {@Value("dong")private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

XML与注解比较
–XML可以适用任何场景 ,结构清晰,维护方便
–注解不是自己提供的类使用不了,开发简单方便

xml与注解整合开发 :推荐最佳实践
–xml管理Bean
–注解完成属性注入
–使用过程中, 可以不用扫描,扫描是为了类上的注解

补充:
使用JavaConfig的方式配置Spring,可以用一个配置类代替xml配置

写一个配置类

package com.config;import com.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Configuration //这个也会被spring容器托管,注册到容器中,因为他本来就是一个@Component
@ComponentScan("com.pojo")
@Import(Config2.class)
public class MyConfig {@Beanpublic User getUser(){return new User();}}

将加载xml上下文改成加载config上下文

import com.config.MyConfig;
import com.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Mytest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);User user = (User) context.getBean("getUser");System.out.println(user);}
}

五.AOP

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

AOP可以在不改变原有代码的基础上,通过动态代理从切面增加新的功能。

主流的动态代理方式有两种:java原生 和 cglib

java原生的动态代理需要实现接口,cglib不用

springboot2.0之前默认使用javaJDK的动态代理,2.0以后默认cglib,可以通过手动配置去修改默认的配置。

JDK的动态代理需要了解两个类 : InvocationHandler 和 Proxy

1.InvocationHandler & Proxy

InvocationHandler:调用处理程序

每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用将被编码并分派到其调用的invoke方法。

看例子里面的Client中调用proxy.rent(),相当于就是通过反射,将rent方法的信息作为method参数,调用了代理类中的invoke方法。

Object invoke(Object proxy, 方法 method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理的超类。

自己写一个代理类继承InvocationHandler,重写invoke方法,
写一个getProxy方法,通过Proxy的newProxyInstance静态方法获取proxy实例

package com;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//会这个类,自动生成代理类
public class ProxyInvocation implements InvocationHandler {//被代理的接口private Rent rent;public void setRent(Rent rent) {this.rent = rent;}//生成代理类public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);}//处理代理实例,并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {seeHouse();Object result = method.invoke(rent, args);fare();return result;}public void seeHouse(){System.out.println("see house");}public void fare(){System.out.println("fare");}
}
package com;public class Client {public static void main(String[] args) {//真实角色Host host = new Host();//代理角色ProxyInvocation proxyInvocation = new ProxyInvocation();//通过调用程序处理角色来处理我们要调用的接口对象proxyInvocation.setRent(host);Rent proxy = (Rent) proxyInvocation.getProxy();  //这里的proxy是动态生成的proxy.rent();}}

2.Spring中的AOP

spring使用的是最广泛的aspectJ

提供声明式事务;允许用户自定义切面

以下名词需要了解下:

  1. 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
  2. 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  3. 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  4. 目标(Target):被通知对象。
  5. 代理(Proxy):向目标对象应用通知之后创建的对象。
  6. 切入点(PointCut):切面通知 执行的 “地点”的定义。
  7. 连接点(JointPoint):与切入点匹配的执行点
  8. 切点函数(execution):(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?

提供五种类型的Advice:

  1. 前置通知 继承MethodBeforeAdvice @Before
  2. 后置通知 继承AfterReturningAdvice(有返回值)或继承AfterAdvice(无返回值) 重写after Returning或after方法 @After @AfterReturning
  3. 环绕通知 @Around
  4. 异常抛出通知 @AfterThrowing
  5. 引介通知(类中增加新方法)

依赖:

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>

和IOC一样,都可以使用配置文件或者注解实现

方法一:配置文件

public class Log implements MethodBeforeAdvice {//method : 要执行的目标对象的方法//objects : 被调用的方法的参数//Object : 目标对象@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");}
}
public class AfterLog implements AfterReturningAdvice {//returnValue 返回值//method被调用的方法//args 被调用的方法的对象的参数//target 被调用的目标对象@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("执行了" + target.getClass().getName()+"的"+method.getName()+"方法,"+"返回值:"+returnValue);}
}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--注册bean--><bean id="userService" class="com.kuang.service.UserServiceImpl"/><bean id="log" class="com.kuang.log.Log"/><bean id="afterLog" class="com.kuang.log.AfterLog"/><!--aop的配置--><aop:config><!--切入点 expression:表达式匹配要执行的方法--><aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/><!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config></beans>

也可以将advice写入配置文件里,这样自己定义的切片类就不用继承五个advice了。

第一步 : 写我们自己的一个切入类

public class DiyPointcut {public void before(){System.out.println("---------方法执行前---------");}public void after(){System.out.println("---------方法执行后---------");}}

去spring中配置

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/><!--aop的配置-->
<aop:config><!--第二种方式:使用AOP的标签实现--><aop:aspect ref="diy"><aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/><aop:before pointcut-ref="diyPonitcut" method="before"/><aop:after pointcut-ref="diyPonitcut" method="after"/></aop:aspect>
</aop:config>

测试:

public class MyTest {@Testpublic void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");UserService userService = (UserService) context.getBean("userService");userService.add();}
}

方法二:注解实现

注解里的value详解:

execution(* com.kuang.service.UserServiceImpl.*(…)) 方法执行处

从左到右依次是:

  1. execution(): 表达式主体。

  2. 第一个*号:表示返回类型,*号表示所有的类型。

  3. 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法,*号表示所有的类。

  4. *(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

call 方法调用处

和上面的区别可以看这个例子

如果用execution拦截main方法,会拦截第11行

如果用call拦截main,会拦截第8行

常用方法汇总

方法执行:execution(MethodSignature)

方法调用:call(MethodSignature)

构造器执行:execution(ConstructorSignature)

构造器调用:call(ConstructorSignature)

类初始化:staticinitialization(TypeSignature)

属性读操作:get(FieldSignature)

属性写操作:set(FieldSignature)

例外处理执行:handler(TypeSignature)

对象初始化:initialization(ConstructorSignature)

对象预先初始化:preinitialization(ConstructorSignature)

Advice执行:adviceexecution()

切入点指示符

切入点指示符用来指示切入点表达式目的,,在Spring AOP中目前只有执行方法这一个连接点,Spring AOP支持的AspectJ切入点指示符如下:

execution:用于匹配方法执行的连接点;

within:用于匹配指定类型内的方法执行;

this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;

target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;

@within:用于匹配所有持有指定***注解***类型内的方法;

@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的***注解***;

@args:用于匹配当前执行的方法传入的参数持有指定***注解***的执行;

@annotation:用于匹配当前执行方法持有指定***注解***的方法;

package com.kuang.config;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class AnnotationPointcut {@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")public void before(){System.out.println("---------方法执行前---------");}@After("execution(* com.kuang.service.UserServiceImpl.*(..))")public void after(){System.out.println("---------方法执行后---------");}@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("环绕前");System.out.println("签名:"+jp.getSignature());//执行目标方法proceedObject proceed = jp.proceed();System.out.println("环绕后");System.out.println(proceed);}
}

接着:在Spring配置文件中,注册bean,并增加支持注解的配置

<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

补充重点

在切面里无法autowired获取bean,想要使用spring容器中的组件,需要使用通过BeanFactory获取bean或者懒加载需要使用的bean!!!具体使用方法可以参考若依里面的SpringUtils。

通过实现接口BeanFactoryPostProcessor可以获取beanFactory;

通过实现接口ApplicationContextAware可以获取applicationContext;

/*** spring工具类 方便在非spring管理环境中获取bean* * @author ruoyi*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
{/** Spring应用上下文环境 */private static ConfigurableListableBeanFactory beanFactory;private static ApplicationContext applicationContext;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {SpringUtils.beanFactory = beanFactory;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtils.applicationContext = applicationContext;}/*** 获取对象** @param name* @return Object 一个以所给名字注册的bean的实例* @throws org.springframework.beans.BeansException**/@SuppressWarnings("unchecked")public static <T> T getBean(String name) throws BeansException{return (T) beanFactory.getBean(name);}/*** 获取类型为requiredType的对象** @param clz* @return* @throws org.springframework.beans.BeansException**/public static <T> T getBean(Class<T> clz) throws BeansException{T result = (T) beanFactory.getBean(clz);return result;}/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @param name* @return boolean*/public static boolean containsBean(String name){return beanFactory.containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @param name* @return boolean* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException**/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException{return beanFactory.isSingleton(name);}/*** @param name* @return Class 注册对象的类型* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException**/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException{return beanFactory.getType(name);}/*** 如果给定的bean名字在bean定义中有别名,则返回这些别名** @param name* @return* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException**/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException{return beanFactory.getAliases(name);}/*** 获取aop代理对象* * @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker){return (T) AopContext.currentProxy();}/*** 获取当前的环境配置,无配置返回null** @return 当前的环境配置*/public static String[] getActiveProfiles(){return applicationContext.getEnvironment().getActiveProfiles();}/*** 获取当前的环境配置,当有多个环境配置时,只获取第一个** @return 当前的环境配置*/public static String getActiveProfile(){final String[] activeProfiles = getActiveProfiles();return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;}
}

六.SpringBoot集成MyBatis

spring需要在xml中配置dataSource、sqlSessionFactory

不过现在都用springboot了,就直接讲一下springboot的yml常用配置吧~

# MyBatis配置
mybatis:# 搜索指定包别名typeAliasesPackage: com.example.**.domain# 配置mapper的扫描,找到所有的mapper.xml映射文件mapperLocations: classpath*:mapper/**/*Mapper.xml

typeAliasesPackage可以允许我们在mapper中,resultType只写类名,不需要写完整的com.**的路径

mapperLocations是我们需要扫描的mapper位置,通过通配符可以从不同的地方拿到mapper.xml

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency>

七.SpringBoot配置事务

参考博文:https://blog.csdn.net/wkl305268748/article/details/77619367

简介以及使用

在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式。
编程式事务管理: 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务管理: 建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单。

  1. 通过@Transactional,实现了事务操作。
  2. Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,因此对于我们自定义异常,通过rollbackFor进行设定
  3. 如果我们需要捕获异常后,同时进行回滚,通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();进行手动回滚操作。
  4. 使用Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
    设置回滚点,使用TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);回滚到savePoint。

注解参数

  • readOnly:该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
  • rollbackFor:该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
  • rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
    noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
  • noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
  • propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
  • isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
  • timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时

事务属性

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。

TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。

TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
默认为读写事务。

Spring初窥门径相关推荐

  1. spring boot项目 中止运行 最常用的几种方法

    spring boot项目 中止运行 最常用的几种方法: 1. 调用接口,停止应用上下文 @RestController public class ShutdownController impleme ...

  2. html+spring boot简单的ajax数据传输实现

    本篇讲解在前后端不分离情况下的html+spring boot的项目数据传输实现 首先,后台我写了三个接口 package com.demo.ajax.controller;import com.de ...

  3. Spring Boot整合Spring Data JPA操作数据

    一. Sping Data JPA 简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套 JPA 应用框架,底层使用了 Hibernate 的 J ...

  4. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  5. Spring cloud 微服务docker容器化最佳实践

    Spring cloud 是当下最炙手可热的微服务套件,我们将介绍如何整合Docker容器达到高效快捷的构建发布 采用了dockerfile-maven-plugin插件发布镜像到远程docker主机 ...

  6. ssh(Struts+spring+Hibernate)三大框架整合-简述

    ssh(Struts+spring+Hibernate)三大框架配合使用来开发项目,是目前javaee最流行的开发方式,必须掌握: 注意: 为了稳健起见,每加入一个框架,我们就需要测试一下,必须通过才 ...

  7. Strutsw2与Spring整合流程-简述

    1.      新建WEB工程: 2.      导入struts2开发包,和资源配置文件 ① globalMessages.properties ② struts.properties 3.     ...

  8. spring Bean自动装配

    spring Bean自动装配 自动装配是使用spring满足bean依赖的一种方式. spring会在应用上下文中为某个bean寻找其依赖的bean. spring自动装配需要从两个角度来实现,或者 ...

  9. spring IOC创建对象方式

    spring IOC创建对象方式 通过无参构造来创建 验证方法: 创建实体类: public class User {private String name;public User() {System ...

  10. 第一个spring程序

    第一个spring程序: 第一步:导入jar包. 新建maven项目: <dependency><groupId>org.springframework</groupId ...

最新文章

  1. “chaos”的算法--之链表面试题
  2. 如何让机器人持续地进行模仿学习(IROS 2021)
  3. USE平台构件属性无法显示的一种解决办法
  4. tars框架php,TarsPHP: TARS-PHP是针对php使用tars二进制协议,以及tars平台整体运维、RPC等一系列能力的解决方案...
  5. Linux的Makefile简单实例教程
  6. 对tensorflow中的tensor、placeholder及feed_dict的理解
  7. Java速成课程建议
  8. Oracle 查看表空间的使用情况SQL语句
  9. 淘宝开源项目TbSchedule的部署和使用
  10. 选择适合esx服务器的性能,VMWare ESX Server性能调整
  11. AAAI 2021论文推荐丨图神经网络成研究热点
  12. 玩转移远SC60 Android开发板------(1)LCD
  13. ActiveMQ 无法访问管理页面
  14. BAPI货物移动时报错
  15. poiExcel格式设置,很好用,感谢大佬
  16. 监控摄像头清晰度(分辨率)介绍
  17. android 手机资源获取失败,三、解决android手机IMEI获取失败终极方案,自定义IMIE,主板+系统定制商+cup指令集+设备参数+显示屏参数+修订版列表等参数生成IMIEI...
  18. 计算机模拟太阳系,科学家通过计算机模拟发现太阳系十九颗小行星或来自系外...
  19. 微信提现功能测试点【杭州多测师】【杭州多测师_王sir】
  20. Linux窗口和Win命令窗口查看mysql bit类型的值

热门文章

  1. 如何改变计算机内存配置文件,电脑内存使用率过高怎么解决?教你如何调整内存大小...
  2. 锐意创新,引领音视频未来
  3. numpy求矩阵特征值与特征向量
  4. C语言里面100UL是什么意思
  5. Eclipse的各种查找,类的查找,方法查找快捷键
  6. rdkitnlp | smiles数据扩增与smiles标准化
  7. 如何写出一份完美的BP(商业计划书)?
  8. 计算单词的长度C++
  9. 5分钟摄像头抓拍一次,居家一天至少89次!尚德员工:连厕所都不敢上
  10. C语言程序设计期末考试试题(含答案)