zoukankan      html  css  js  c++  java
  • spring事务管理方式,aop

    达内12 note unit 09 01

    1.spring事务管理

    2.spring提供了对事务管理支持

    spring采用aop机制完成事务控制

    可以实现在不修改原有组件代码情况下实现事务控制功能。

    spring提供了两种事务管理方式:

    a。编程式事务管理(编写java代码)

      TransactionTemplate

    b.声明式事务管理(编写配置,大家都用这种)

      xml版本配置

      注解版本配置

      --配置DataSourceTransactionManager

      --开启事务注解配置<tx:annotation>

      --在目标组件方法前添加@Transactional

    注解版本例子:

    例如UserServiceImpl中的regist注册方法需要事务:

    第一步,我们现在applicationContext.xml中配置事务管理组件

    <!--  配置事务管理组件 -->

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

      <property name="dataSource" ref="dbcp"></property>

    </bean>

    <!--  开启事务注解标记@Transactional -->

    <!--  当调用带@Transactional 标记的方法时,将txManager事务管理功能切入到方法-->

    <tx:annotation-driven transaction-manager="txManager"/>

    第二步,在所有service类上,加上@Transactional注解

    package org.alexhe.note.service;

     

    import javax.annotation.Resource;

     

    import org.alexhe.note.dao.IUserDao;

    import org.alexhe.note.entity.NoteResult;

    import org.alexhe.note.entity.User;

    import org.alexhe.note.util.NoteUtil;

    import org.springframework.stereotype.Service;

     

    @Service("userService")

    @Transactional//这里加入事务注解

    public class UserServiceImpl implements IUserService{

    @Resource

    private IUserDao userDao;//注入

    @Override

    public NoteResult checkLogin(String name, String pwd) throws Exception {

    // TODO Auto-generated method stub

    NoteResult result=new NoteResult();

    User user=userDao.findByName(name);

    if(user==null){

    result.setStatus(1);

    result.setMsg("用户名不存在");

    return result;

    }

     

    String md5_pwd=NoteUtil.md5(pwd);

    if(!user.getCn_user_password().equals(md5_pwd)){

    result.setStatus(2);

    result.setMsg("密码不正确");

    return result;

    }

    result.setStatus(0);

    result.setMsg("用户名和密码正确");

    result.setData(user.getCn_user_id());//返回userid

    return result;

    }

    @Override

    public NoteResult regist(String name, String password, String nickname) throws Exception {

    NoteResult result=new NoteResult();

    //检测用户名是否被占用

    User has_user=userDao.findByName(name);

    if(has_user!=null){

    result.setStatus(1);

    result.setMsg("用户名已被占用");

    return result;

    }

    //注册

    User user=new User();

    user.setCn_user_name(name);

    user.setCn_user_desc(nickname);

    String md5_pwd=NoteUtil.md5(password);

    user.setCn_user_password(md5_pwd);//设置加密的密码

    String userId=NoteUtil.createId();

    user.setCn_user_id(userId);//设置userid

    //调用userDao保存

    userDao.save(user);

    result.setStatus(0);

    result.setMsg("注册成功");

    return result;

    }

     

    }

    xml版本配置例子:(配置比注解版复杂)

    第一步,我们现在applicationContext.xml中配置事务管理组件,记得xml里加入aop的头

    <!--  配置事务管理组件 -->

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

      <property name="dataSource" ref="dbcp"></property>

    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">

      <tx:attributes><!--  哪些方法用事务,就写在里面 -->

        <tx:method name="regist"/>

        <tx:method name="checkLogin"/>

        <tx:method name="add*"/> <!--  以add开头的所有方法 -->

       <!--  <tx:method name="*"/> <!--  所有方法都加注释 -->

      </tx:attributes>

    </tx:advice>

    <aop:config>

      <aop:pointcut id="target" expression="within(org.alexhe.note.service..*)"/> <!--  expression代表哪个组件,作用在哪些组件上,这里代表service包及其下面的所有组件-->

      <aop:advisor advice-ref="txAdvice" pointcut-ref="target"/> 

    </aop:config>

    3.Spring对事务管理的控制

    a。控制事务可读可写特性

    Spring分为可读写事务和只读事务。默认为可读写,一般只涉及查询操作,建议用只读事务

    @Transactional(readOnly=true)

    b.控制事务是否回滚

    Spring遇到runtimeException异常,会回滚。遇到非运行时异常,不会回滚。

    @Transactional(readOnly=true,rollbackFor=IOException.class)   这样遇到IOException也会发生回滚。

    建议:自定义异常继承自RuntimeException继承

    public class MyException extends RuntimeException   

    c。控制事务传播类型

     遇到带有事务控制方法调用另一个事务控制方法时,可以选择合适的传播类型,默认是required类型,后者使用前者事务。

    d。控制事务隔离级别

    @Transactional(readOnly=true, isolation=Isolation.READ_COMMITED);

    由低到高如下:

    READ_UNCOMMITED读未提交

    READ_COMMITED读已提交

    REPEATABLE_READ可重复读

    SERIALIZABLE序列化操作

    DEFAULT默认,根据数据库隔离级别自动选择,

    4.spring aop应用

    aop编程优点:可以动态将一个组件功能切入到指定的目标方法上。可以使结构更加灵活,也能实现组件重复利用。

    aop编程:更注重于业务逻辑隔离,将一些共通处理逻辑和传统处理逻辑解耦。

    例如事务处理,日志记录,异常处理等等。

    适用环境:

      --共通处理逻辑

      --调用时机相同

    例子,用xml配置方式,往controller上加方法:

    1.新建了一个aspect包(非必须)

    2.包里新建一个类,然后新建一个clogger方法。表示加上日志功能。

    3.spring的文件里加配置,把需要aop的controller加上第二步类里的方法

    package org.alexhe.note.aspect;

     

    public class NoteLogger {

     

    public void clogger(){

    System.out.println("进入Controller处理");

    }

    }

     

     

    spring的配置:

    <!-- aop示例 -->

    <bean id="noteLogger" class="org.alexhe.note.aspect.NoteLogger"></bean>

    <aop:config>

    <!-- 把上面的noteLogger定义为切面组件 -->

    <aop:aspect ref="noteLogger">

    <!-- 什么时候,向哪些方法上切入 --><!-- 在controler包及其子包下,所有执行的方法前,加入clogger方法  -->

    <aop:before method="clogger" pointcut="within(org.alexhe.note.controller..*)"/> 

    </aop:aspect>  

    </aop:config>

    例子,用注解方式,往service层加方法:

    spring配置不用上面这一坨,只要加上:

    <!-- 开启aop注解支持,@Aspect,@通知标记 -->

    <aop:aspectj-autoproxy />

    java类:

    package org.alexhe.note.aspect;

     

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.Before;

    import org.springframework.stereotype.Component;

     

    @Component//扫描,将组件扫描到Spring容器

    @Aspect//将当前组件设置为切面组件

    public class ServiceLogger {

     

    @Before("within(org.alexhe.note.service..*)")//service下面所有方法加入这个slooger方法

    public  void slogger(){

    System.out.println("进入service方法");

    }

    }

    =====AOP应用=====

    a。要切入什么功能

    b。要切入的时机,什么时候切入,通知。

      前置通知,在原有方法前插入新功能。@Before

      后置通知,在执行完原有方法后,调入新的切面方法。@AfterReturning

      异常通知,在原有方法出异常了,调入新的切面方法。@AfterThrowing

      最终通知,不管有没有异常,最终都要走他。@After

      环绕通知=前置+后置

    try{

      前置通知@Before

      //目标方法处理

      后置通知@AfterReturning

    }catch(){

      异常通知@AfterThrowing

    }finally{

      最终通知@After

    }

    c。往那些组件方法切入-->切入点

      --类型限定表达式

      within(类型)

      与类型匹配的组件都是目标

      within(org.service.UserService)

      within(org.service.*) 仅限于当前包下

      within(org.service..*) 当前包和子包下

      --方法限定表达式

      execution(修饰符 返回类型 方法名(参数) 抛出异常)     返回类型和方法名参数是必须的,其他可以省略

      execution(* find*(..))     必须是find开头的方法,参数返回值不限制

      execution(* org.service.UserService.regist*(..))   

      execution(* org.service..*.*(..))   

    上述表达式可以使用 !,&&,|| 运算符连接。

    案例:将异常信息写入文件

    package org.alexhe.note.aspect;

     

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.AfterThrowing;

    import org.springframework.stereotype.Component;

     

    @Component//扫描,将组件扫描到Spring容器

    @Aspect//将当前组件设置为切面组件

    public class ExceptionLogger {

     

    @AfterThrowing(throwing="e",pointcut="within(org.alexhe.note.service..*)")//service下面所有方法加入这个log方法

    public  void log(Exception e){

    System.out.println(e);

    }

    }

  • 相关阅读:
    D触发器的使用小结
    CAN通信帧ID的含义解析? (转载)
    mcp2515屏蔽寄存器和过滤寄存器的学习
    spi调试步骤,mcp2515调试整理
    最近工作小结2019.11.24
    Can总线上的电平及物理层仲裁
    can总线学习网上资料汇总
    can总线的远程帧(遥控帧)—说的很形象
    在IAR平台建立STC8ASK64S4A12单片机工程
    cortex-m系列的区别(图解)及今日碎片学习笔记
  • 原文地址:https://www.cnblogs.com/alexhjl/p/7815878.html
Copyright © 2011-2022 走看看