Spring框架/技术
- 一、简介
- Spring简介
- 常用jar包
- 二、Spring-IOC(控制反转)
- IOC简介
- Spring-IOC程序搭建步骤
- 解决Spring配置文件没有提示
- BeanFactory和ApplicationContext
- 关系
- 区别
- Bean的创建
- Bean标签的属性
- Bean的装配方式
- 动态装配方式
- 静态装配方式
- Bean的作用域
- IOC简介
- 三、DI依赖注入
- 环境
- 简单类型注入
- 集合类型注入
- 域属性自动注入
- 自动注入的类别
- 空值注入
- 构造注入
- DI之注解
- 常用注解
- 环境
- 四、Spring-AOP(面向切面)
- 介绍
- 代理模式
- 作用
- 分类
- 静态代理
- jdk动态代理
- cglib动态代理
- 基于Schema-based方式的通知声明
- 搭建编程环境
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 基于AspectJ方式之注解的方式通知声明
- 搭建编程环境
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- 基于AspectJ方式之配置文件的方式通知声明
- 通知类的声明
- 配置文件的声明
- 五、Spring的事物管理
- 事物的ACID特性
- DataSourceTransactionManager与HibernateTransactionManager
- TransactionDefinition接口
- 事物的传播行为
一、简介
Spring简介
Spring是为了 解决企业应用开发的复杂性 而创建的一个开源框架;是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 IoC : Inversion of Control 控制反转 AOP : Aspect Oriented Programming 依赖注入
常用jar包
1.spring-core.jar core是spring框架基本的核心工具类。spring其他组件都要使用到这个jar的类。是其他组件的基本核心。外部依赖Commons Logging, (Log4J)。 2.spring-beans.jar beans是基本的jar。他包含访问配置文件,创建和管理bean,以及控制反转,注入操作的所有相关类。如果只用到Ioc/DI,则只需引入core与beans就足够了。平常用的Autowired就是用的这个包的 3.spring-aop.jar 这个jar 文件包含在应用中使用Spring 的AOP 特性时所需的类和源码级元数据支持。使用基于AOP 的Spring特性,如声明型事务管理(Declarative Transaction Management),也要在应用里包含这个jar包。 4.spring-context.jar 这个 jar 文件为 Spring 核心提供了大量扩展。可以找到使用 Spring ApplicationContext 特性时所需的全部类, JDNI 所需的全部类, UI 方面的用来与模板 (Templating) 引擎如 Velocity、 FreeMarker、JasperReports 集成的类,以及校验 Validation 方面的相关类。 5.spring-webmvc.jar 这个 jar 文件包含 Spring MVC 框架相关的所有类。包含国际化、标签、Theme、视图展现的 FreeMarker、JasperReports、Tiles、Velocity、XSLT 相关类。当然,如果你的应用使用了 独立的 MVC 框架,则无需这个 JAR 文件里的任何类。 6.spring-jdbc.jar 这个jar 文件包含对Spring 对JDBC 数据访问进行封装的所有类。 7.spring-web.jar 这个jar 文件包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web Application Context 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类。平时用到RequestMapping就是来自这个包的.
其他jar包
二、Spring-IOC(控制反转)
IOC简介
控制反转(IoC,Inversion of Control),是一个概念,是一种思想。 控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。把对象的创建、初始化、 销毁等工作交给spring容器来做。由spring容器控制对象的生命周期。undefined
Spring-IOC程序搭建步骤
1、导入jar包 2、创建spring配置文件(src目录下) 3、Bean的定义与注册 4、从spring容器中获取Bean
相关jar包
注:
代码语言:javascript复制 <!-- bean的定义:以下配置相当于创建一个类的对象。即:
SomeServiceImpl someServiceImpl= new SomeServiceImpl(); -->
<bean id="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
解决Spring配置文件没有提示
如果在没有网络的情况下,spring中基于联网的 .xsd配置文件的约束文件会无法使用,这样就需要我们其提前下载并手动添加到本地,步骤如下:
- 找到XML Catalog,添加下载好的约束文件
- 注意如下选项并保存
BeanFactory和ApplicationContext
关系
ApplicationContext 是 Spring 应用程序中的中央接口,用于向应用程序提供配置信息 它继承了 BeanFactory 接口,所以 ApplicationContext 包含 BeanFactory 的所有功能以及更多功能!它的主要功能是支持大型的业务应用的创建特性。
区别
BeanFactory当调用getBean获取相应对象时,才创建对象 ApplicationContext容器初始化时,所有的容器中的bean创建完毕
Bean的创建
在applicationContext.xml的< beans>标签中创建< bean>标签,一个< bean>标签表示一个java对象 ,该对象由Spring容器创建和管理,
Bean标签的属性
标签 | 属性 |
---|---|
id | 唯一标示该bean |
name | 和id相同的作用 |
class | 该类的权限定名,指向对于的类 |
autowire | 表示bean的自动装配 |
Bean的装配方式
Bean的装配,即Bean对象的创建 Bean的装配方式有三种 第一种:spring从两个角度实现自动化装配:组件扫描和自动装配。 第二种:通过java代码装配bean 第三种:在XML中装配bean
动态装配方式
代码语言:javascript复制1、创建Bean对象 2、注册工厂,创建工厂对象 3、从工厂中获取someServiceImpl的bean对象
public class ServiceFactory {
//动态工厂方式,创建bean对象
public SomeService getSomeFactory(){
SomeService someServiceImpl=new SomeServiceImpl();
return someServiceImpl;
}
}
代码语言:javascript复制<!-- 注册工厂 -->
<bean id="serviceFactory" class="com.bjsxt.factory.ServiceFactory"></bean>
<!-- 从工厂中获取someServiceImpl的bean对象 -->
<bean id="someServiceImpl" factory-bean="serviceFactory" factory-method="getSomeFactory"></bean>
代码语言:javascript复制public class SomeTest {
//该方式的优点:实现了测试类与service实现类的解耦合
@Test
public void someTest01(){
//创建容器对象,ApplicationContext容器初始化时,所有的容器中的bean创建完毕
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeService service = ac.getBean("someServiceImpl", SomeService.class);
service.doSome();
}
}
静态装配方式
代码语言:javascript复制1、创建bean对象 2、从工厂中获取someServiceImpl的bean对象
<!-- 静态工厂配置,类名对象,类名,方法 -->
<bean id="someServiceImpl" class="com.bjsxt.factory.ServiceFactory" factory-method="getSomeFactory"></bean>
Bean的作用域
作用域名 | 作用 |
---|---|
singleton | 默认使用, 在整个Spring IoC 容器中,使用 singleton 定义的Bean将只有一个实例 |
prototype | 原型模式,每次通过容器的getBean 方法获取prototype定义的Bean 时,都将产生一个新的Bean实例 |
request | 对于每次HTTP请求,使用request定义的Bean都将产生一个新的实例,每次HTTP请求都将产生不同的Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效 |
Session | 对于每次HTTP Session ,使用session定义的Bean都将产生一个新实例,该作用域仅在给予web的Spring ApplicationContext情形下有效 |
global session | 每个全局得HTTP Session对应一个Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效 |
三、DI依赖注入
依赖注入(Dependency Injection):这就是DI,字面上理解,依赖注入就是将服务注入到使用它的地方。对象只提供普通的方法让容器去决定依赖关系,相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。 所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
环境
演示所用的两个实体类
测试类的测试方法
代码语言:javascript复制 @Test
public void someTest01(){
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Star star =ac.getBean("star", Star.class);//getBean(id, class)
System.out.println(star);
}
简单类型注入
代码语言:javascript复制简单类型数据注入包括普通数据注入、引用数据类型注入
<bean id="star" class="com.bjsxt.pojo.Star" >
<!-- 简单数据类型 -->
<property name="name" value="旭旭宝宝"></property>
<property name="age" value="39" ></property>
<!-- 引用数据类型注入参考的是下面的id -->
<property name="partener" ref="partener" ></property>
</bean>
<bean id="partener" class="com.bjsxt.pojo.Partener" >
<property name="name" value="韩茜茜"></property>
</bean>
集合类型注入
每种集合类型使用的标签
简单案例
代码语言:javascript复制<bean id="someService" class="com.bjsxt.pojo.SomeService" >
<property name="myArray">
<array>
<value>北京</value>
<value>上海</value>
</array>
</property>
<property name="myList">
<list>
<value>男</value>
<value>女</value>
</list>
</property>
<property name="mySet">
<set>
<ref bean="partener1" />
<ref bean="partener2" />
</set>
</property>
<property name="myMap">
<map>
<entry key="qq" value="1315690999"></entry>
<entry key="moblie" value="18326989999"></entry>
</map>
</property>
<property name="myProps">
<props >
<prop key="兴趣">看动漫</prop>
<prop key="爱好">敲代码</prop>
</props>
</property>
</bean>
域属性自动注入
域属性自动注入的方式 全局自动注入(根标签下) :default-autowire 局部自动注入(注册bean时使用): autowire=“byType”
自动注入的类别
byName 方式域属性自动注入,根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配 byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配
空值注入
代码语言:javascript复制空字符串注入:通过value标签 <property name="name" ><value/></property>
空值注入:通过null标签 <property name="name" ><null/></property>
构造注入
代码语言:javascript复制 1、通过name属性的构造
<constructor-arg name="name" value="郭靖"></constructor-arg>
2、通过index属性的构造,但value的类型顺序必须与构造器中的类型一致
<constructor-arg index="0" value="郭靖"></constructor-arg>
3、自动构造,但value的类型顺序必须与构造器中的类型一致
<constructor-arg value="郭靖"></constructor-arg>
DI之注解
在使注解注入用前需要扫描使用注解的包
代码语言:javascript复制<context:component-scan base-package="com.bjsxt.pojo"></context:component-scan>
常用注解
代码语言:javascript复制@Service 该注解添加在 Service的实现类中
@Controller 该注解添加在 Controller类的前面,表明当前controller交给spring管理
@Autowired 引用数据类型注入,默认byType。常用于controller与service的实现类中
@Qualifier(“id”) 与@Autowired 联合使用 byName 方式注入
@Value 简单数据类型注入。常用于自定义配置文件中的值的引用。
@Resource 引用数据类型默认使用 byName 方式,若找不到名称匹配的bean ,才会采用 byType 方式
@Scope() 表明采取什么作用域。单态模式singleton:默认使用原型模式prototype:每次调用都会传建一个新的bean
四、Spring-AOP(面向切面)
介绍
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
代理模式
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。 二十三种设计模式之一 ,详情见本连接第三部分
作用
可以隐藏目标类的具体实现 在不修改目标类代码的情况下能够对其功能进行增强。
分类
静态代理
代码语言:javascript复制测试静态代理,写一个接口,一个目标实现类,再写一个代理类也实现该接口,并将目标类对象传入代理类中,代理类调用目标类对象的方法。最后测试。 注意: 代理类与目标类实现相同的接口
public class SomeTest {
public static void main(String[] args) {
//定义目标对象
SomeService target = new SomeServiceImpl();
//定义目标对象的代理对象
SomeService proxy = new ServiceProxy(target);
String result = proxy.doSome();
System.out.println(result);
}
}
jdk动态代理
代码语言:javascript复制动态代理不在程序中声明代理类代码,而是在运行中使用 Proxy 类 动态执行代理类的方法。 应用场景:目标类
public class SomeTest {
public static void main(String[] args) {
//定义目标对象
final SomeService target = new SomeServiceImpl();
//定义目标对象的代理对象
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),//目标类的类加载器
target.getClass().getInterfaces(),//目标类实现的所有接口
new InvocationHandler() {//调用处理器
//proxy:代理对象
//method:目标方法
//args:目标方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String result = (String) method.invoke(target, args);
return result.toUpperCase();
}
});
String result1 = proxy.doSome();
System.out.println(result1);
}
}
cglib动态代理
代码语言:javascript复制应用场景: 实现目标类没有实现目标接口 注意: CGLIB 代理需要引入 cglib 架包
public class SomeTest {
public static void main(String[] args) {
//定义目标对象
SomeServiceImpl target = new SomeServiceImpl();
//定义目标对象的代理对象
SomeServiceImpl proxy = new CglibProxyFactory(target).proxyCreator();
String result1 = proxy.doSome();
System.out.println(result1);
}
}
基于Schema-based方式的通知声明
搭建编程环境
- 导入jar包(SpringIOC包 AOP包)
- 在src下创建applicationcontext.xml配置文件
- 编写通知类.相关的接口 ,实现类以及方法
- 由Spring容器对象获取切点所在bean对象调用切点方法完成功能操作。(注册通知类 注册切面 指定目标对象 指定目标接口 指定切面)
- 运行测试
接口类
代码语言:javascript复制public interface SomeService {
void doSome();
String doOther();
}
实现类
代码语言:javascript复制public class SomeServiceImpl implements SomeService {
public SomeServiceImpl() {
System.out.println("无参构造器执行!");
}
@Override
public void doSome() {
System.out.println("doSome()方法执行!");
}
@Override
public String doOther() {
System.out.println("doOther()方法执行!");
return "return doOther";
}
}
测试方法类
代码语言:javascript复制public class SomeTest {
//该方式的优点:实现了测试类与service实现类的解耦合
@Test
public void someTest01(){
//创建容器对象,ApplicationContext容器初始化时,所有的容器中的bean创建完毕
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeService service = ac.getBean("proxyFactoryBean", SomeService.class);
service.doSome();
String result = service.doOther();
System.out.println(result);
}
}
配置文件
代码语言:javascript复制<?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="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
<!-- 注册切面,前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.bjsxt.aspects.MyMethodBeforeAdvice"></bean>
<!-- 注册切面,后置通知 -->
<bean id="afterReturning" class="com.bjsxt.aspects.AfterReturning"></bean>
<!-- 注册切面,环绕通知 -->
<bean id="myMethodInterceptor" class="com.bjsxt.aspects.MyMethodInterceptor"></bean>
<!-- 注册切面,异常通知 -->
<bean id="myThrowsAdvice" class="com.bjsxt.aspects.MyThrowsAdvice"></bean>
<!-- 注册代理 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定目标对象 -->
<property name="target" ref="someServiceImpl"></property>
<!-- 指定目标类实现所有接口,接口,接口所在类 -->
<property name="interfaces" value="com.bjsxt.service.SomeService"></property>
<!-- 指定切面 -->
<!-- <property name="interceptorNames" value="myMethodBeforeAdvice"></property> -->
<!-- <property name="interceptorNames" value="afterReturning"></property> -->
<property name="interceptorNames" value="myMethodInterceptor"></property>
<!-- <property name="interceptorNames" value="myThrowsAdvice"></property> -->
</bean>
</beans>
前置通知
代码语言:javascript复制/**
* 前置通知
* method:目标方法
* args:目标方法参数列表
* target:目标对象
*/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("MyMethodBeforeAdvice.before(前置通知执行)");
}
}
后置通知
代码语言:javascript复制/**
* 后置通知
* returnValue:目标方法的返回值
*
*/
public class AfterReturning implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("AfterReturning.afterReturning(后置通知方法的执行)" returnValue);
if (returnValue!=null) {
System.out.println("AfterReturning.afterReturning()" ((String)returnValue).toUpperCase());
}
}
}
环绕通知
代码语言:javascript复制/**
* 切面:环绕通知
* invocation:方法调用器
*
*/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation ) throws Throwable {
System.out.println("环绕通知:目标方法执行之前");
//调用执行目标方法
Object result = invocation.proceed();
if (result!=null) {
result=((String)result).toUpperCase();
}
System.out.println("环绕通知:目标方法执行之后");
return result;
}
}
异常通知
代码语言:javascript复制/**
* 切面:异常通知
* 需要自己创建
*
*/
public class MyThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("异常通知执行!!!");
}
}
基于AspectJ方式之注解的方式通知声明
搭建编程环境
- 创建目标类(接口以及实现类测试类)
- 定义通知类,在前置通知方法上添加相应的注解,表示是什么通知
- 创建配置文件(注册目标类,注册切面,注册自动代理)
- 运行测试类
接口类
代码语言:javascript复制public interface SomeService {
void doSome();
String doOther();
}
实现类
代码语言:javascript复制public class SomeServiceImpl implements SomeService {
public SomeServiceImpl() {
System.out.println("无参构造器执行!");
}
@Override
public void doSome() {
System.out.println("doSome()方法执行!" 1/0);
//System.out.println("doSome()方法执行!");
}
@Override
public String doOther() {
System.out.println("doOther()方法执行!");
return "love";
}
}
测试类
代码语言:javascript复制public class SomeTest {
@Test
public void someTest01(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeService service = ac.getBean("someServiceImpl", SomeService.class);
service.doSome();
String result = service.doOther();
System.out.println(result);
}
}
配置文件
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册目标类 -->
<bean id="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
<!-- 注册切面 -->
<bean id="myAspect" class="com.bjsxt.aspects.MyAspect"></bean>
<!-- 注册自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
前置通知
代码语言:javascript复制@Before("execution(* *..service.*.doSome(..))")
public void before(){
System.out.println("前置通知方法执行!");
}
后置通知
代码语言:javascript复制@AfterReturning(value="execution(* *..service.*.doOther(..))",returning="result")
public void afterReturning(Object result){
System.out.println("后置通知方法执行! 目标方法的返回值是" result);
}
环绕通知
代码语言:javascript复制@Around("execution(* *..service.*.doOther(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知:目标方法执行之前!");
String result = (String) pjp.proceed();
if(result!=null){
result = result.toUpperCase();
}
异常通知
代码语言:javascript复制@AfterThrowing(valujavae="execution(* *..service.*.doSome(..))",throwing="ex")
public void throwing(Exception ex){
System.out.println("异常通知方法执行! 异常信息为:" ex);
}
最终通知
代码语言:javascript复制@After("execution(* *..service.*.doSome(..))")
public void after(){
System.out.println("最终通知方法执行!");
System.out.println("最终方法的作用是,无论是否出现异常,都会执行该通知。类似try...catch中的finally代码块");
}
基于AspectJ方式之配置文件的方式通知声明
通知类的声明
代码语言:javascript复制public class MyAspect {
//该注解表明当前方法是前置通知方法
/*
public void before(){
System.out.println("前置通知方法执行!");
}
public void before(JoinPoint jp){
System.out.println("前置通知方法执行!jp=" jp);
}
*/
//该注解表明当前方法是后置通知方法
/*
public void afterReturning(Object result){
System.out.println("后置通知方法执行! 目标方法的返回值是" result);
}
*/
//该注解表明当前方法是环绕通知方法
/*
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知:目标方法执行之前!");
String result = (String) pjp.proceed();
if(result!=null){
result = result.toUpperCase();
}
System.out.println("环绕通知:目标方法执行之后!");
return result;
}
*/
//该注解表明当前方法是异常通知方法
/*
public void throwing(Exception ex){
System.out.println("异常通知方法执行! 异常信息为:" ex);
}
*/
//该注解表明当前方法是最终通知方法
public void after(){
System.out.println("最终通知方法执行!");
}
}
配置文件的声明
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册目标类 -->
<bean id="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
<!-- 注册切面 -->
<bean id="myAspect" class="com.bjsxt.aspects.MyAspect"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* *..service.*.doSome(..))" id="doSomePC"/>
<aop:pointcut expression="execution(* *..service.*.doOther(..))" id="doOtherPC"/>
<aop:aspect ref="myAspect">
<!-- <aop:before method="before" pointcut-ref="doSomePC"/> -->
<!-- <aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="doSomePC"/> -->
<!-- <aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="doOtherPC" returning="result"/> -->
<!-- <aop:around method="around" pointcut-ref="doOtherPC"/> -->
<!-- <aop:after-throwing method="throwing(java.lang.Exception)" pointcut-ref="doSomePC" throwing="ex"/> -->
<aop:after method="after" pointcut-ref="doSomePC"/>
</aop:aspect>
</aop:config>
</beans>
五、Spring的事物管理
事物的ACID特性
特性 | 介绍 |
---|---|
原子性(Atomicity) | 一个事务里面所有包含的SQL语句是一个执行整体,不可分割,要么都做,要么都不做。 |
一致性(Consistency) | 事务开始时,数据库中的数据是一致的,事务结束时,数据库的数据也应该是一致的。 |
隔离性(Isolation) | 是指数据库允许多个并发事务同时对其中的数据进行读写和修改的能力,隔离性可以防止事务的并发执行时,由于他们的操作命令交叉执行而导致的数据不一致状态。 |
持久性 (Durability) : | 是指当事务结束后,它对数据库中的影响是永久的,即便系统遇到故障的情况下,数据也不会丢失。 |
DataSourceTransactionManager与HibernateTransactionManager
名称 | 区别 |
---|---|
DataSourceTransactionManager | 此事务管理器是针对传统的JDBC进行事务管理,在spring中是对JdbcTemplate进行事务管理 |
HibernateTransactionManager | 是对Hibernate进行事务管理,当在spring中使用HibernateTemplate时,要使用此管理器。 |
注:当在service的一个方法中同时使用了JdbcTemplate和HibernateTemplate时,就要使用HibernateTransactionManager了,因为当使用DataSourceTransactionManager时,JdbcTemplate和HibernateTemplate获得的connection并不是同一个,也就没办法对service的方法进行事务管理了。
TransactionDefinition接口
Spring的TransactionDefinition接口中定义了如下事务相关常量
常量名 | 作用 |
---|---|
int getPropagationBehavior(); | 返回事务的传播行为 |
int getIsolationLevel(); | 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据 |
String getName(); | 返回事务的名字 |
int getTimeout(); | 返回事务必须在多少秒内完成 |
boolean isReadOnly(); | 返回是否优化为只读事务。 |
事物的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。 例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
TransactionDefinition定义中包括了如下几个表示传播行为的常量:
常量 | 作用 |
---|---|
TransactionDefinition.PROPAGATION_REQUIRED: | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 |
TransactionDefinition.PROPAGATION_SUPPORTS: | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 |
TransactionDefinition.PROPAGATION_MANDATORY: | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
不支持当前事务的情况:
常量 | 作用 |
---|---|
TransactionDefinition.PROPAGATION_REQUIRES_NEW: | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行, | 如果当前存在事务,则抛出异常。 |
其他情况
常量 | 作用 |
---|---|
TransactionDefinition.PROPAGATION_NESTED: | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED(创建一个新的事务)。 |