Spring | 事务没有生效导致数据没有持久化的探究

今天遇到一个很诡异的问题,在使用 Hibernate 持久化数据时,数据没有写入到数据库,其他正常的查询数据都是没有问题的。

1 事务配置

spring-context.xml 中事务的配置



    




    
        
        
        
        
        
        
        
        

        
        
        
        
    







    
    

复制代码

配置中同时使用了两种风格的事务支持,一种是切面式的一种是注解式的

经过仔细的 Debug 和排查,发现 Service 中的持久化操作没有被包裹在事务中执行。至于其他的异常和数据库的原因统统被排除掉。经过一步步的调试,发现是配置的问题(spring-servlet.xml)。

2 spring-servlet.xml 的配置

原来的配置:





    
    
    

复制代码

3 原因探究

其实核心问题还是 spring-context.xmlspring-servlet.xml 的关系没有完全理清导致出现的问题。

因为 Spring 应用中 spring-context.xmlspring-servlet.xml 对应的容器是父子容器,spring-context.xml 对应的是父容器,spring-servlet.xml对应的是子容器。

子容器配置扫描的 Controller 进行扫描装配 Service 时装配了 @Service 注解的 Bean(没有被事务包裹),因为 spring-servlet.xml 优先于 spring-context.xml,导致子容器此时得到的是原样的Service(没有经过事务加强处理,故而没有事务处理能力)。

其实正常情况下 Bean 应该由父容器进行初始化以保证事务的增强处理(因为事务的配置在 spring-context.xml 中)。

关系理清之后,问题的解决方式其实很简单,核心就一条,保证 spring-servlet.xml 在扫描的时候尽量只扫描控制器,如果是单个 Servlet 内部使用的 bean,可以根据业务自行调整。

所以下文简单列举了几种修改方式。类推,不仅仅是事务包裹的 Service,其他类似的业务也是如此。

下面列举几种修改方式,配置修改成下面的情形都可正常持久化

第一种情况:排除使用 Service 注解的类

重点关注 context:exclude-filter 标签


    
    
    
    
    

复制代码

第二种情况:只专注扫描 controller


    
    
    

复制代码

第三种情况:设置 use-default-filters="false"

注意 use-default-filters="false" 这个属性:默认为 true,会扫描包含Service, Component, Repository, Controller 注解修饰的类,配置成 false,只扫描指定的注解。


    
    
    

你可能感兴趣的:(spring,java,servlet)