Spring⾯试,IoC和AOP的理解,@Transactional原理及使⽤spring 的优点?
1.降低了组件之间的耦合性,实现了软件各层之间的解耦
2.可以使⽤容易提供的众多服务,如事务管理,消息服务等
3.容器提供单例模式⽀持
4.容器提供了AOP技术,利⽤它很容易实现如权限拦截,运⾏期监控等功能
5.容器提供了众多的辅助类,能加快应⽤的开发
6.spring对于主流的应⽤框架提供了集成⽀持,如hibernate,JPA,Struts等
7.spring属于低侵⼊式设计,代码的污染极低
8.独⽴于各种应⽤服务器
9.spring的DI机制降低了业务对象替换的复杂性
10.Spring的⾼度开放性,并不强制应⽤完全依赖于Spring,开发者可以⾃由选择spring的部分或全部
什么是DI机制?
依赖注⼊(Dependecy Injection)和控制反转(Inversion of Control)是同⼀个概念,具体的讲:当某个⾓⾊
需要另外⼀个⾓⾊协助的时候,在传统的程序设计过程中,通常由调⽤者来创建被调⽤者的实例。但在spring中
创建被调⽤者的⼯作不再由调⽤者来完成,因此称为控制反转。创建被调⽤者的⼯作由spring来完成,然后注⼊调⽤者
因此也称为依赖注⼊。
spring以动态灵活的⽅式来管理对象,注⼊的两种⽅式,设置注⼊和构造注⼊。
设置注⼊的优点:直观,⾃然
构造注⼊的优点:可以在构造器中决定依赖关系的顺序。
什么是AOP?
⾯向切⾯编程(AOP)完善spring的依赖注⼊(DI),⾯向切⾯编程在spring中主要表现为两个⽅⾯
1.⾯向切⾯编程提供声明式事务管理
2.spring⽀持⽤户⾃定义的切⾯
⾯向切⾯编程(aop)是对⾯向对象编程(oop)的补充,
⾯向对象编程将程序分解成各个层次的对象,⾯向切⾯编程将程序运⾏过程分解成各个切⾯。
AOP从程序运⾏⾓度考虑程序的结构,提取业务处理过程的切⾯,oop是静态的抽象,aop是动态的抽象,
是对应⽤执⾏过程中的步骤进⾏抽象,,从⽽获得步骤之间的逻辑划分。
aop框架具有的两个特征:
1.各个步骤之间的良好隔离性
2.源代码⽆关性
Spring @Transactional原理及使⽤
spring ioc注解本⽂主要讨论Spring声明式事务中使⽤注解@Transactional的⽅式、原理及注意事项,主要包括以下内容:Spring @Transactional的配置使⽤;
Spring @Transactional的传播⾏为和隔离级别;
Spring @Transactional的⼯作原理;
Spring @Transactional的注意事项;
Spring @Transactional⾃我调⽤中的问题。
1、Spring @Transactional的配置
步骤⼀、在Spring配置⽂件中引⼊命名空间
1 2 3 4 5 6 7<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:tx="/schema/tx"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans-2.0.xsd /schema/tx
/schema/tx/spring-tx-2.0.xsd">
步骤⼆、xml配置⽂件中,添加事务管理器bean配置
<!-- 事务管理器配置,单数据源事务 -->
<bean id="pkgouTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="pkGouDataSource" />
</bean>
<!-- 使⽤annotation定义事务 -->
<tx:annotation-driven transaction-manager="pkgouTransactionManager" />
步骤三、在使⽤事务的⽅法或者类上添加 @Transactional(“pkgouTransactionManager”)注解
2、 Spring @Transactional的传播⾏为和隔离级别
1> 事务注解⽅式: @Transactional
标注在类前:标⽰类中所有⽅法都进⾏事务处理
标注在接⼝、实现类的⽅法前:标⽰⽅法进⾏事务处理
2> 事务传播⾏为介绍:
事务传播⾏为说明
@Transactional(propagation=Propagation.REQUIRED)如果有事务,那么加⼊事务,没有的话新建⼀个(默认情况)
@Transactional(propagation=Propagation.NOT_SUPPORTED)容器不为这个⽅法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)不管是否存在事务,都创建⼀个新的事务,原来的挂起,新的执⾏完毕,
继续执⾏⽼的事务
@Transactional(propagation=Propagation.MANDATORY)必须在⼀个已有的事务中执⾏,否则抛出异常
@Transactional(propagation=Propagation.NEVER)必须在⼀个没有的事务中执⾏,否则抛出异常(与
Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)如果其他bean调⽤这个⽅法,在其他bean中声明事务,那就⽤事务。如
果其他bean没有声明事务,那就不⽤事务
3> 事务超时设置:
@Transactional(timeout=30) //默认是30秒
4> 事务隔离级别:
事务隔离级别说明
@Transactional(isolation = Isolation.READ_UNCOMMITTED)读取未提交数据(会出现脏读,不可重复读),基本不使⽤@Transactional(isolation = Isolation.READ_COMMITTED)(SQLSERVER默认)读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)串⾏化
脏读 : ⼀个事务读取到另⼀事务未提交的更新数据
不可重复读 : 在同⼀事务中,多次读取同⼀数据返回的结果有所不同,换句话说,后续读取可以读到另⼀事务已提交的更新数据。相反,”可重复读”在同⼀事务中多次读取数据时,能够保证所读数据⼀样,也就是后续读取不能读到另⼀事务已提交的更新数据
幻读 : ⼀个事务读到另⼀个事务已提交的insert数据
@Transactional的属性:
3、 Spring @Transactional的⼯作原理
⾃动提交
默认情况下,数据库处于⾃动提交模式。每⼀条语句处于⼀个单独的事务中,在这条语句执⾏完毕时,如果执⾏成功则隐式的提交事务,如果执⾏失败则隐式的回滚事务。
事务管理,是⼀组相关的操作处于⼀个事务之中,因此必须关闭数据库的⾃动提交模式。这点,Spring会在
org/springframework/jdbc/datasource/DataSourceTransactionManager.java中将底层连接的⾃动提交特性设置为false。
1 2 3 4 5 6 7 8 9 10 11 12// switch to manual commit if necessary。 this is very expensive in some jdbc drivers,// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already)。if (con。getautocommit())
{
txobject.setmustrestoreautocommit(true);
if (logger.isdebugenabled())
{
logger.debug("switching jdbc connection [" + con + "] to manual commit");
}
//⾸先将⾃动提交属性改为false
con.setautocommit(false);
}
spring事务回滚规则
Spring事务管理器回滚⼀个事务的推荐⽅法是在当前事务的上下⽂内抛出异常。Spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,Spring只有在抛出的异常为运⾏时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的⼦类(Errors也会导致事务回滚)。⽽抛出checked异常则不会导致事务回滚。
Spring也⽀持明确的配置在抛出哪些异常时回滚事务,包括checked异常。也可以明确定义哪些异常抛出时不回滚事务。
还可以编程性的通过setRollbackOnly()⽅法来指⽰⼀个事务必须回滚,在调⽤完setRollbackOnly()后你所能执⾏的唯⼀操作就是回滚。
在上⼀篇⽂章中,我们使⽤了声明式事务来配置事务,使事务配置从service逻辑处理中解耦出来。但它还存在⼀些缺点:
1. 我们只针对⽅法名的特定进⾏拦截,但⽆法利⽤⽅法签名的其它信息定位,如修饰符、返回值、⽅法⼊参、异常类型等。如果我们需要为同名不同参的同载⽅法配置不同事务就会出问题了。
2. 事务属性的配置串虽然能包含较多信息,但配置较易出错。
针对这些问题,我们可以基于Schema,引⼊tx和aop的命名空间来改进我们的配置:
1. 引⼊命名空间
<beans xmlns="/schema/beans"
xmlns:mvc="/schema/mvc" xmlns:aop="/schema/aop"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd
/schema/tx /schema/tx/spring-tx-3.2.xsd
/schema/aop /schema/aop/spring-aop-3.1.xsd">
1. tx\aop核⼼配置
<!-- 配置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRES_NEW" />
<tx:method name="update*" propagation="REQUIRES_NEW" />
<tx:method name="delete*" propagation="REQUIRES_NEW" />
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切⼊点,以及把事务切⼊点和事务属性关联起来 -->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* service.*.*(..))"
id="ServicePointcut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="ServicePointcut" />
</aop:config>
这⾥需要特别注意的是,我们需要在标签中将proxy-target-class配置成true,否则会出现和上⼀篇⽂章相同的错误:我们定义的类⽆法转换成代理类
这⾥我们通过来配置我们的事务增强属性。在标签中,常见属性及其说明如下,其中,除了name属性是必选外,其他都是可选的:
属性说明默认允许值
name匹配⽅法名必须声明,
⾄少为*
可使⽤*通配符
propagation事务传播⾏为REQUIRED REQUIRED,SUPPORTS和MANDATORY和REQUIRES_NEW 和NOT_SUPPORTED和NEVER和NESTED
read-only设置当前事务是否只读false true,false
isolation事务隔离级别DEFAULT READ_UNCOMMITTED和READ_COMMITTED和REPEATABLE_READ和SERIALIZABLE
timeout设置事务的超时时间-1默认由顶层事务系统决定
rollback-for内容为异常名,表⽰当抛出这些异常时事务回
滚,可以⽤逗号分隔配置多个
⽆默认值可以使⽤异常名称的⽚段进⾏匹配如ception等
no-rollback-for 内容为异常名,表⽰当抛出这些异常时继续提交
事务,可以⽤逗号分隔配置多个
⽆默认值可以使⽤异常名称的⽚段进⾏匹配如ception等。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论