Java_Spring第四天笔记(事务)

回顾

1,组件扫描过滤器

  • xml版

    <!--组件扫描-->
    <context:component-scan base-package="com.itheima">
        <!--排除service注解-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
    
  • 注解版

    @ComponentScan(
            value = "com.itheima",
            excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Service.class)
    )
    

2,AOP

概述: 面向切面编程。是一种思想。而spring对AOP思想进行了实现。

术语:

  • 连接点
  • 切入点
  • 通知
  • 切面 --> 切入点和通知的关系
  • 织入

切入点表达式:

excution(返回值类型 包名.类名.方法名(参数类型))

通知类型:

  • 前置通知
  • 后置通知
  • 返回时通知
  • 异常通知
  • 环绕通知
<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
    <aop:aspect ref="myAdvice">
        <aop:after-returning method="afterReturing" pointcut-ref="pt"/>
        <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
        <aop:after method="after" pointcut-ref="pt"/>
        <aop:before method="before" pointcut-ref="pt"/>
        <!--<aop:around method="around" pointcut-ref="pt"/>-->
    </aop:aspect>
</aop:config>

今日内容

  1. 注解版的AOP使用
  2. 案例
  3. AOP底层原理
  4. 事务管理
    1. 编程式事务
    2. 声明式事务(掌握)

1,AOP实现(注解+xml)

在这里插入图片描述

2,开启aop注解驱动

  • xml方式

    <aop:aspectj-autoproxy/>
    
  • 注解方式

    在配置类上加下面的注解

    @EnableAspectJAutoProxy
    

3,AOP底层原理(了解)

3.1 装饰者模式

3.2 jdk的动态代理

//1,如何获取动态代理对象
/*
    动态代理: 在运行过程中动态的增强功能
         代理类: 在内存中生成
         代理类是接口的子实现类

     参数:
         ClassLoader loader : 获取当前类的字节码对象,然后获取类加载器
              为什么需要传递类加载器呢?用来加载代理类的
         Class<?>[] interfaces : 接口的字节码对象数组
               指定代理类的父接口
         InvocationHandler h : 方法调用的处理程序

 */
UserService userService = (UserService) Proxy.newProxyInstance(
    Demo.class.getClassLoader(),
    new Class[]{UserService.class},
    new InvocationHandler() {

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("我被执行了");
            return null;
        }
    }
);

//通过代理对象调用方法
userService.save();

注意:

  1. 代理类和目标类的关系是兄弟关系

3.3 CGLIB代理

核心对象

Enhancer

注意:

1.代理类和目标类是子父关系

2.代理类动态的在内存中生成

3.目标类不能使用final修饰

4.要增强的方法不能使用final修饰

 public static UserService createUserServiceCglibProxy(Class clazz) throws IllegalAccessException, InstantiationException {
        //创建Enhancer对象(可以理解为内存中动态创建了一个类的字节码)
        Enhancer enhancer = new Enhancer();
        //设置Enhancer对象的父类是指定类型UserServerImpl
        enhancer.setSuperclass(clazz);
        //设置回调方法
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //通过调用父类的方法实现对原始方法的调用
                Object ret = methodProxy.invokeSuper(o, args);
                //后置增强内容,与JDKProxy区别:JDKProxy仅对接口方法做增强,cglib对所有方法做增强,包括Object类中的方法
                if(method.getName().equals("save")) {
                    System.out.println("刮大白3");
                    System.out.println("贴墙纸3");
                }
                return ret;
            }
        });
        //使用Enhancer对象创建对应的对象
        UserService userService = (UserService) enhancer.create();
        System.out.println(userService);
        if(true) {
            while(true) {}
        }
        return userService;
    }

AOP的原理:

默认使用的是jdk的动态代理。

spring会根据目标类有没有实现接口判断,如果实现了,使用jdk的动态代理,如果没有实现,使用CGLIB代理。

当然我们也可以通过设置,使目标类无论是否实现接口,都使用CGLIB代理。

<!---注解方式的aop-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<!--xml方式的AOP-->
<aop:config proxy-target-class="true">
</aop:config>

//纯注解
@EnableAspectJAutoProxy(proxyTargetClass = true)

面试题:

聊聊AOP的原理。

小扩展:设计模式有23种接触到的有以下几种:

  • 单例模式

  • 工厂模式

    • 简单工厂模式
    • 工厂方法模式
    • 抽象工厂模式
  • 代理

    • 静态代理 : 屏蔽对象

      public class UserServiceImplDecorator implements UserService {
      
          private UserService userService = new UserServiceImpl();
      
          public void save() {
              //原始调用
              userService.save();
              //增强功能(后置)
              System.out.println("刮大白");
          }
      }
      
    • 动态代理

  • 构建者模式

  • 模板方法模式

  • 装饰者模式 : 对业务对象进行增强

    public class UserServiceImplDecorator implements UserService {
    
        private UserService userService;
    
        public UserServiceImplDecorator(UserService userService){
            this.userService  = userService;
        }
    
        public void save() {
            //原始调用
            userService.save();
            //增强功能(后置)
            System.out.println("刮大白");
        }
    }
    
    要求:
    	1.装饰者类和业务类实现相同的接口
    	2.在装饰者类中提供一个业务接口的成员变量
    	3.提供一个构造方法给成员变量进行赋值。
    

4,事务控制

概述: 逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

ACID(酸性):一致性,原子性,隔离性,持久性

隔离级别:

  • read uncommitted
  • read committed (oracle)
  • Repeatable (mysql)
  • Serializable

4.1 编程式事务控制(了解)

  • 事务相关对象 (知道)
    • 平台事务管理器 PlatformTransactionManager --> DataSourceTransactionManager
    • 事务定义对象 TransactionDefinition
    • 事务状态对象 TransactionStatus
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    private DataSource dataSource;
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }



    public void transfer(String outName, String inName, Double money) {
        //开启事务
        PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
        //事务定义
        TransactionDefinition td = new DefaultTransactionDefinition();
        //事务状态
        TransactionStatus ts = ptm.getTransaction(td);

        try {
            accountDao.inMoney(outName, money);
            int i = 1 / 0;
            accountDao.outMoney(inName, money);
            //提交事务
            ptm.commit(ts);
        } catch (Exception e) {
            ptm.rollback(ts);
            throw new RuntimeException(e);
        }
    }

}

AOP改进

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String outName, String inName, Double money) {
        accountDao.inMoney(outName,money);
        int i = 1/0;
        accountDao.outMoney(inName,money);
    }
}

通知类:

public class TxAdvice {

    private DataSource dataSource;
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Object transactionManager(ProceedingJoinPoint pjp) {
        //开启事务
        PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
        //事务定义
        TransactionDefinition td = new DefaultTransactionDefinition();
        //事务状态
        TransactionStatus ts = ptm.getTransaction(td);

        Object ret = null;
        try {
            //执行目标方法
            ret = pjp.proceed(pjp.getArgs());
            //提交事务
            ptm.commit(ts);
        } catch (Throwable e) {
            ptm.rollback(ts);
            throw new RuntimeException(e);
        }
        return ret;
    }

}

配置:

<bean id="txAdvice" class="com.itheima.aop.TxAdvice">
    <property name="dataSource" ref="dataSource"/>
</bean>

<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
    <aop:aspect ref="txAdvice">
        <aop:around method="transactionManager" pointcut-ref="pt"/>
    </aop:aspect>
</aop:config>

4.2 声明式事务控制(掌握)

4.2.1 基于xml的

只需要进行配置即可

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--定义事务管理的通知类-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!--定义控制的事务-->
    <tx:attributes>
        <tx:method name="*" read-only="false"/>
        <tx:method name="find*" read-only="true"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="pt" expression="execution(* com.itheima.service.*Service.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>

说明:spring对aop思想进行了实现,aspectj也对aop进行了实现,spring中的aop不好用,spring将aspectj整合进来了。

advisor和aspect区别:

  • advisor是spring aop原生的配置
    • 要求通知类必须实现相对应的接口。比如前置通知 MethodBeforeAdvice
  • aspect是spring整合aspectj提供声明切面的标签

事务传播行为(理解)

概述:一个方法调用另一个方法,对事务的态度。

4.2.2 基于注解的
  • 配置(开启声明式事务控制注解支持)

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <tx:annotation-driven transaction-manager="txManager"/>
    
  • 在service层接口内添加注解

    @Transactional(readOnly = true)
    public interface AccountService {
    
        /**
         * 转账操作
         * @param outName     出账用户名
         * @param inName      入账用户名
         * @param money       转账金额
         */
    
        @Transactional
        public void transfer(String outName, String inName, Double money);
    
        public void findAll();
        
        public void findById(int id);
    }
    
4.2.3 纯注解开发
@EnableTransactionManagement

开启注解支持相关的配置说明:

<!--包扫描   IOC-->
<context:component-scan base-package="com.itheima"/>

<!--开启aop注解的支持-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--事务管理注解驱动-->
<tx:annotation-driven transaction-manager="txManager"/>

重点小结:

  • aop注解

    • @Aspect : 声明切面,用在通知类上
    • @Before : 前置通知,用在方法上
    • @After : 后置通知,用在方法上
    • @AfterReturning
    • @AfterThrowing
    • @Around
    • @Pointcut : 切入点:用在空方法上
  • 开启aop注解驱动

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
  • 事务控制

    • 声明式事务控制(xml|注解)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值