Spring事物、面向切面编程、依赖注入简介

简介:

常用的spring的功能主要是事物、面向切面编程(AOP)、依赖注入(IOC)。下文不涉及到具体的代码,只为了说明一些概念的理解。


事物:

事务级别:
ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 
ISOLATION_READ_COMMITTED  保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ  这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。 
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。


事务传播行为:
1: PROPAGATION_REQUIRED 加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务 
比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚 
2: PROPAGATION_SUPPORTS 如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行 
3: PROPAGATION_MANDATORY 必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常 
4: PROPAGATION_REQUIRES_NEW 这个就比较绕口了。比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。 
5: PROPAGATION_NOT_SUPPORTED 当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。 
6: PROPAGATION_NEVER 不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。 
7: PROPAGATION_NESTED 理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。 而Nested事务的好处是他有一个savepoint。

其中需要特别对比说明下的是:

1. PROPAGATION_REQUIRES_NEW会开启很多事务,外部事务挂起,里面的事务独立执行,对性能的损耗较大。PROPAGATION_NESTED为父子事务,实际上是借助jdbc的savepoint实现的,属于同一个事物。
2. PROPAGATION_NESTED的回滚可以总结为,子事务回滚到savepoint,父事务可选择性回滚或者不不滚;父事务回滚子事务一定回滚。



名称分析:

1: Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。 
2: non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。 
3: phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。 Dirty reads non-repeatable reads phantom reads 
Serializable 不会 不会 不会 
REPEATABLE READ 不会 不会 会 
READ COMMITTED 不会 会 会 
Read Uncommitted 会 会 会



readOnly:

概念:从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)

应用场合:

如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性; 
如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】

怎样设置:

对于只读查询,可以指定事务类型为readonly,即只读事务。
由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。

(1)在JDBC中,指定只读事务的办法为: connection.setReadOnly(true);

(2)在Hibernate中,指定只读事务的办法为: session.setFlushMode(FlushMode.NEVER); 
此时,Hibernate也会为只读事务提供Session方面的一些优化手段

(3)在Spring的Hibernate封装中,指定只读事务的办法为: bean配置文件中,prop属性增加“readOnly”或者用注解方式@Transactional(readOnly=true)
【 if the transaction is marked as read-only, Spring will set the Hibernate Session’s flush mode to FLUSH_NEVER, and will set the JDBC transaction to read-only】也就是说在Spring中设置只读事务是利用上面两种方式在将事务设置成只读后,相当于将数据库设置成只读数据库,此时若要进行写的操作,会出现错误



Timeout:
在事务属性中还有定义“timeout”值的选项,指定事务超时为几秒。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。


事物回滚:

Throwable是所有异常的根,java.lang.Throwable 
Error是错误,java.lang.Error 
Exception是异常,java.lang.Exception,Exception分为Checked异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。


Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚。

在@Transaction注解中定义noRollbackFor和RollbackFor指定某种异常是否回滚。 
@Transaction(noRollbackFor=RuntimeException.class) 
@Transaction(RollbackFor=Exception.class) 
这样就改变了默认的事务处理方式。



AOP:

AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种 散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为 “Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低 模块间的耦合度,并有利于未来的可操作性和可维护性。

举个简单的清除某个对象缓存的例子:假如某个对象有多份缓存,用一个方法来封装了这个清除缓存的操作,其他修改修改这个对象的内容的操作都需要在后面单独调用一次清除缓存的方法。如果使用AOP技术,我们只需要定义一个切面表达式,定义一个后通知就可以达到上面的效果了,不需要每个方法都去单独调用一次。

以下是一些术语:

1.切面(aspect):指横切性关注点的抽象即为切面(系统模块化的一个切面或领域),它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象,如日志记录。 

2.连接点(Joinpoint):所谓连接点是指那些被拦截到的点。在spring中,只支持拦截方法,因为spring只支持方法类型的连接点,连接点可以是方法、field、类构造器或异常抛出点。

3.通知(Advice):切面的实际实现,他通知系统新的行为。是指在什么连接点做什么动作。 

4.切入点(Pointcut):表达式表示的连接点集合,表达式是一个规则用来表示与连接点匹配的规则。 

5.引入(Introduction):在不修改类代码的前提下,为类添加新的方法和属性,分静态和动态引入。 

6.目标对象(target):被通知的对象。  

7.织入(Weave):将切面应用到目标对象从而创建一个新代理对象的过程。织入发生在目标对象生命周期的多个点上。


注意环绕方法通知,环绕方法通知要注意必须给出调用之后的返回值,否则被代理的方法会停止调用并返回null,除非你真的打算这么做(之前被这个问题搞了很久,不报错什么不正常的都没有,就是执行结果不正确)。


IOC:

IOC(Inversion of Control),翻译为控制反转。DI(Dependency Injection)依赖注入是控制反转的一种实现方式,DI的命名最早是由Martin Fowler、Rod Johnson和PicoContainer等大虾于2003年命名的。假设A依赖于B,传统编程理念一般会在A中声明B类型的成员变量,然后由A来负责创建B的实例,或者由A调用工厂方法来获取B的实例。按照依赖注入的理念,A依赖于B,不是由A来负责创建B的实例,而是由容器来负责创建B的实例,并将B的实例注入到A中,一般通过构造参数注入和setter方法注入的方 式。从控制对象的角度来说,控制对象从A转变成了容器,从A主动创建管理B转变成了B被容器创建好后主动注入到A,这就是控制反转。

spring具体的实现包括set注入、构造器注入、静态工厂方法注入等。



本文转自 古道卿 51CTO博客,原文链接:http://blog.51cto.com/gudaoqing/1272419
相关文章
|
1月前
|
开发框架 Java Spring
Spring依赖注入以及使用建议
Spring依赖注入以及使用建议
30 0
|
1月前
|
Java Spring
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
94 0
|
2月前
|
Java 数据库连接 应用服务中间件
Spring5源码(39)-Aop事物管理简介及编程式事物实现
Spring5源码(39)-Aop事物管理简介及编程式事物实现
24 0
|
2月前
|
XML Java 程序员
Spring的依赖注入
Spring的依赖注入
|
2月前
|
Java Spring
Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
|
1月前
|
Java 数据库连接 API
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
49 0
|
11天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
25 0
切面编程的艺术:Spring动态代理解析与实战
|
2月前
|
设计模式 开发框架 Java
Spring 依赖注入方式有哪些?
Spring 依赖注入方式有哪些?
83 0
Spring 依赖注入方式有哪些?
|
2月前
|
设计模式 Java 测试技术
Spring依赖注入的魔法:深入DI的实现原理【beans 五】
Spring依赖注入的魔法:深入DI的实现原理【beans 五】
124 0
|
2月前
|
安全 Java 开发者
Spring依赖注入大揭秘:@Autowired、@Qualifier和@Resource的区别与应用
Spring依赖注入大揭秘:@Autowired、@Qualifier和@Resource的区别与应用
55 0