资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,Spring,高级事务管理,难点剖析,1-1,:,DAO,和事务管理的牵绊,问题:,很少使用,Spring,但不使用,Spring,事务管理器的应用,因此常常有人会问:是否用了,Spring,,就一定要用,Spring,事务管理器,否则就无法进行数据的持久化操作呢?事务管理器和,DAO,是什么关系呢?,1-2,:,DAO,和事务管理的牵绊,真相:,答案当然是否定的!我们都知道:事务管理是保证数据操作的事务性(即原子性,一致性,隔离性,持久性,也即所谓的,ACID,),脱离了事务性,,DAO,照样可以顺利地进行数据的操作。,2-1,:,应用分层的迷惑,问题:,Web,,,Service,及,DAO,三层划分就像西方国家的立法、行政、司法三权分立一样被奉为金科玉律,是否要使用,Spring,的事务管理就一定先要进行三层的划分呢?是否每一层都需要有接口,+,实现类呢?,2-2,:,应用分层的迷惑,真相:,应用代码分层和,Spring,的事务管理是两回事,没有应用分层照样可以进行,Spring,事务管理。,Spring,的事务管理也不依赖于接口,+,实现类的开发模式。,3-1,:,事务方法嵌套调用的迷茫,问题:,一个事务方法调用另一个事务方法会产生两个事务,还是只有一个事务?,3-2,认识,TransactionDefinition,int getPropagationBehavior(),:事务的传播行为,int getIsolationLevel(),:事务的隔离级别,int getTimeout(),:事务的过期时间,boolean isReadOnly(),:事务的读写特性。,很明显,除了事务的传播行为外,事务的其它特性,Spring,是借助底层资源的功能来完成的,,Spring,无非只充当个代理的角色。但是事务的传播行为却是,Spring,凭借自身的框架提供的功能,3-3 Spring,事务传播行为,PROPAGATION_REQUIRED,:,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。,PROPAGATION_SUPPORTS,:,支持当前事务,如果当前没有事务,就以非事务方式执行。,PROPAGATION_MANDATORY,:,使用当前的事务,如果当前没有事务,就抛出异常。,PROPAGATION_REQUIRES_NEW,:,新建事务,如果当前存在事务,把当前事务挂起。,PROPAGATION_NOT_SUPPORTED,:,以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。,PROPAGATION_NEVER,:,以非事务方式执行,如果当前存在事务,则抛出异常。,PROPAGATION_NESTED,:,如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。,所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。,Spring,支持,7,种事务传播行为,3-4,:,事务方法嵌套调用的迷茫,真相:,Spring,默认的事务传播行为是,PROPAGATION_REQUIRED,,它适合于绝大多数的情况。假设,ServiveX#methodX(),都工作在事务环境下(即都被,Spring,事务增强了),假设程序中存在如下的调用链:,Service1#method1()-Service2#method2()-Service3#method3(),,那么这,3,个服务类的,3,个方法通过,Spring,的事务传播机制都工作在同一个事务中。,4-1,:,多线程的困惑,问题:,如果在一个,ServiceA,和,a(),方法中启动一个线程,在这个新创建的线程中执行,ServiceB,的事务方法,b(),,,ServiceA,的,a(),方法和,ServiceB,的,b(),方法是工作在同一事务环境中,还是分别拥有一个独立的事务呢,?,4,-2,:多线程的困惑,真相:,在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,不同线程下的事务方法工作在独立的事务中。,5-1,:,联合军种作战的混乱,问题:,Hibernate,Spring JDBC,iBatis,等多种数据持久方法如何联合使用,会存在哪些问题,如何进行事务管理的配置,?,5-2,:,如何配置事务管理器,如果你采用了一个高端,ORM,技术(,Hibernate,,,JPA,,,JDO,),同时采用一个,JDBC,技术(,Spring JDBC,,,iBatis,),由于前者的会话(,Session,)是对后者连接(,Connection,)的封装,,Spring,会,“,足够智能地,”,在同一个事务线程让前者的会话封装后者的连接。所以,我们只要直接采用前者的事务管理器就可以了。下表给出了混合数据访问技术所对应的事务管理器:,5-3:,丢失更新,由于,Hibernate,一级缓存的原因,在通过,save,update,delete,等方法操作数据时,并没有真正向数据库发送,SQL,,只有调用,flush(),时,,Hibernate,才会将一级缓存中的状态变化同步到数据库中。,Hibernate,的事务管理在提交事务时,会自动调用,flush(),操作,将一级缓存同步到数据库中,此时才会将产生并向数据库发送,SQL,语句。,正是因为以上原因的存在,所有在混合使用,JDBC,和,Hibernate,时,可能存在丢失更新的问题。,Hibernate:,user.setMark(30);,session.update(user),JDBC:,“,update t_user set mark=mark+10,”,开始事务,结束事务,Hibernate,同步一级缓存,1.,“,update t_user set mark=30,”,2.,提交事务,最终,user,的,mark,为,30,JDBC,的更改被覆盖,5-4:,缓存不同步,在混合使用,Hibernate,和,JDBC,时,,JDBC,的操作不会同步到,Hibernate,的缓存中(一级缓存及二级缓存),,Hibernate,缓存中的状态变更也不被,JDBC,感知。因此混合使用时必须特别关注这一点。,5-5:,混合使用最佳实践,由于混合数据访问技术的方案的事务同步而缓存不同步的情况,所以最好用,Hibernate,完成读写操作,而用,Spring JDBC,完成读的操作。如用,Spring JDBC,进行简要列表的查询,而用,Hibernate,对查询出的数据进行维护。如果确实要同时使用,Hibernate,和,Spring JDBC,读写数据,则必须充分考虑到,Hibernate,缓存机制引发的问题:必须充分分析数据维护逻辑,根据需要,及时调用,Hibernate,的,flush(),方法,以免覆盖,Spring JDBC,的更改,在,Spring JDBC,更改数据库时,维护,Hibernate,的缓存。,6-1,:,特殊方法成漏网之鱼,问题:,是否配置了,Spring,事务,AOP,增强后,服务方法就可以工作在事务环境中呢?,Spring,的事务增强有哪些限制条件,哪些方法需要特别关注?,6-2,:,特殊方法成漏网之鱼,真相:,由于,Spring,事务管理是基于接口代理或动态字节码技术,通过,AOP,实施事务增强的。,对于基于接口动态代理的,AOP,事务增强来说,由于接口的方法是,public,的,这就要求实现类的实现方法必须是,public,的(不能是,protected,,,private,等),同时不能使用,static,的修饰符。所以,可以实施接口动态代理的方法只能是使用,“,public,”,或,“,public final,”,修饰符的方法,其它方法不可能被动态代理,相应的也就不能实施,AOP,增强,也即不能进行,Spring,事务增强了。,基于,CGLib,字节码动态代理的方案是通过扩展被增强类,动态创建子类的方式进行,AOP,增强植入的。由于使用,final,static,private,修饰符的方法都不能被子类覆盖,相应的,这些方法将不能被实施的,AOP,增强。所以,必须特别注意这些修饰符的使用,以免不小心成为事务管理的漏网之鱼。,7-1,:,数据连接泄漏,问题:,是否使用,Spring,的事务管理后,就没有数据连接泄漏的问题了?哪些情况下会发生连接泄漏问题,如何处理?,7-2,:直接从数据源获取连接,如果我们在事务上下文中直接从数据源直接获取连接,且在使用完成后不主动归还给数据源(调用,Connection#close(),),则将造成数据连接泄漏的问题。,7-3,:,DataSourceUtils,Spring提供了一个能从当前事务上下文中获取绑定的数据连接的工具类,那就是DataSourceUtils。Spring强调必须使用DataSourceUtils工具类获取数据连接,。,static ConnectiondoGetConnection(DataSource dataSource),:首先尝试从事务上下文中获取连接,失败后再从数据源获取连接;,static ConnectiongetConnection(DataSource dataSource),:和,doGetConnection,方法的功能一样,实际上,它内部就是调用,doGetConnection,方法获取连接的;,static voiddoReleaseConnection(Connection con,DataSource dataSource),:释放连接,放回到连接池中;,static voidreleaseConnection(Connection con,DataSource dataSource),:和,doReleaseConnection,方法的功能一样,实际上,它内部就是调用,doReleaseConnection,方法获取连接的;,7-4,:,DataSourceUtils,内部机制,1.,首先尝试从事务上下文获取连接,2.,如果事务上下文没有连接,则直接从数据源获取,3.,如果有事务上下文,将连接绑定上当前的事务上下文中。,7-5,:,使用DataSourceUtils获取数据连接也可能造成泄漏,如果,DataSourceUtils,在没有事务上下文的方法中使用,getConnection(),获取连接,依然会造成数据连接泄漏!,7-6,:,JdbcTemplate,可以,做到对连接泄漏免疫,来看一下JdbcTemplate最核心的一个数据操作方法execute():,7-7,:,其它数据访问技术的等价类,理解了,Spring JDBC,的数据连接泄漏问题,其中的道理可以平滑地推广到其它框架中去。,Spring,为每个数据访问技术框架都提供了一个获取事务上下文绑定的数据连接(或其衍生品)的工具类和数据源(或其衍生品)的代理类。,8,:资源,Spring,事务管理高级应用难点剖析,:,第,1,部分,Spring,事务管理高级应用难点剖析,:,第,2,部分,Spring,事务管理高级应用难点剖析,:,第,3,部分,谢谢!,
展开阅读全文