关于spring aop和spring事务各种配置和一些注意事项

关于spring事务和spring aop

1. spring 事务默认只有抛出unchecked Exception才会回滚

              UncheckedException包括error和runtimeException派生出的所有子类

2.     什么时候才用事务?

对数据库的数据进行批量或连表操作时,为了保证数据的一致性和正确性,我们需要添加事务管理机制进行管理。当对数据库的数据进行操作失败时,事务管理可以很好保证所有的数据回滚到原来的数据,如果操作成功,则保证所有需要更新的数据持久化。

例如:1.转账:A对B转账,需要先把A的钱减掉再把B的钱加上,这两个操作任何一个失败,都要撤销整个转账过程,不然会出大问题。

2.向数据库中插入订单时,先插入订单再插入订单项,这两个操作任何一个失败都会影响数据的一致性,所以必须做事务的处理

3.     Spring事务的配置

    3.1.     声明式事务(不需要开启注解代理等等)

        3.1.1.     配置通知(说明哪些方法需要拦截,被拦截的方法将应用配置好的事务属性)

        3.1.2.     配置切入点需要对哪个类进行事务管理

注意:只会管理通知中有的那些方法

             

              例如:

                     1.<!--通知 -->

       <tx:adviceid="txAdvice" transaction-manager="transactionManager">

              <tx:attributes>

                     <!--传播行为 -->

                     <tx:methodname="save*" propagation="REQUIRED" />

                     <tx:methodname="*” read-only="true">

              </tx:attributes>

       </tx:advice>

       2.<!—针对通知配置切入点-->

<aop:config>

       <!—aop:advisor是针对通知的,如果自己写切面用aop:aspect-->

              <aop:advisoradvice-ref="txAdvice"

                     pointcut="execution(*com.outsider.nh.*.service.*.*(..))" />

       </aop:config>

      

       注:上面的配置就是说会对所有com.outsider.*.service下面的类中的save*方法进行事务管理,而对其他方法只读,这种方法配置起来比较多,可能会针对每个service来配置一个通知和切入端

3.2. 注解事务(这时候不需要再配置第一种方法的那些东西了)

  

    3.2.1.     开启注解事务扫描

<tx:annotation-driventransaction-manager="transactionManager"proxy-target-class="true"/>

    3.2.2.     使用@Transactional在类上或者方法上注解同时可以配置传播行为和隔离级别

在类上配置时,代表会对本类中所有public的方法进行事务管理

4.     Spring事务和spring aop

Spring事务使用了aop这种思想来处理事务,不用我们自己去实现切面类

Spring aop是我们自己写切面来对一些方法做拦截,增强,比如打印日志

5.     Spring aop的配置

写切面,主要实现增强方法,包括前置,后置,环绕等等,需要什么类型就实现,

    5.1.     配置方式

<aop:config>

          <aop:aspect ref="切面bean可以注解扫描进来也可以自己配置bean”>

                 //配置了一个后置通知,method就是增强代码,也是切面中的一个方法,切入点是那些需要被增强的方法

                 <aop:aftermethod="synchIndexForArticleAdd" pointcut="execution(*com.colin.service.impl.ArticleServiceImpl.add*(..))"/>

          </aop:aspect>

   </aop:config>

    5.2    注解方式

        5.2.1.     开启aop自动代理

            <aop:aspectj-autoproxy />

                     关于这个配置详情https://blog.csdn.net/z69183787/article/details/18675145

        5.2.2.    写切面类 典型的如下

//声明这是一个组件

@Component

//声明这是一个切面Bean

@Aspect

public class ServiceAspect {

    private final static Log log = LogFactory.getLog(ServiceAspect.class);

    //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点

    @Pointcut("execution(* com.hyq.aop..*(..))")

    public void aspect(){    }

    /*

     * 配置前置通知,使用在方法aspect()上注册的切入点

     * 同时接受JoinPoint切入点对象,可以没有该参数

     */

    @Before("aspect()")

    public void before(JoinPoint joinPoint){

        System.out.println("执行before.....");

    }

    //配置后置通知,使用在方法aspect()上注册的切入点

    @After("aspect()")

    public void after(JoinPoint joinPoint){

        System.out.println("执行after.....");

    }

    //配置环绕通知,使用在方法aspect()上注册的切入点

    @Around("aspect()")

    public void around(JoinPoint joinPoint){

        long start = System.currentTimeMillis();

        try {

            ((ProceedingJoinPoint) joinPoint).proceed();

            long end = System.currentTimeMillis();

            if(log.isInfoEnabled()){

                log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");

            }

        } catch (Throwable e) {

            long end = System.currentTimeMillis();

            if(log.isInfoEnabled()){

                log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());

            }

        }

    }

    //配置后置返回通知,使用在方法aspect()上注册的切入点

    @AfterReturning("aspect()")

    public void afterReturn(JoinPoint joinPoint){

        if(log.isInfoEnabled()){

            log.info("afterReturn " + joinPoint);

        }

    }

    //配置抛出异常后通知,使用在方法aspect()上注册的切入点

    @AfterThrowing(pointcut="aspect()", throwing="ex")

    public void afterThrow(JoinPoint joinPoint, Exception ex){

        if(log.isInfoEnabled()){

            log.info("afterThrow " + joinPoint + "\t" + ex.getMessage());

        }

    }

}

注意:扫描service层bean时不要扫描到Controller,不然会出现事务无作用!

猜你喜欢

转载自blog.csdn.net/qq_37667364/article/details/79832722