zoukankan      html  css  js  c++  java
  • [ SSH框架 ] Spring框架学习之三(AOP开发和注解的使用)

    一、Spring 使用 AspectJ 进行 AOP 的开发:注解的方式

    1.1 引入相关的jar包

    1.2 引入spring的配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:aop="http://www.springframework.org/schema/aop"
            xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
            <!-- 开启AOP操作 -->
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    
    </beans>

    1.3 编写目标类

    package com.Kevin.aop;
    /**
     * 使用注解方式进行AOP操作
     * 被增强类
     * @author Kevin
     *
     */
    
    public class Book {
        
        public void add(){
            System.out.println("Book Method add----");
        }
    
    }

    1.4 配置目标类 

    <!-- 创建对象 -->
            <bean id="book" class="com.Kevin.aop.Book"></bean>

    1.5 开启aop注解的自动代理

     <!-- 开启AOP操作 -->
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
            

    1.6 AspectJ 的 AOP 的注解 

      ●  Pointcut:切入点,在类中有很多方法可以被增强,而只有实际增强的方法称为切入点;
      ●  Advice:通知/增强,实际增强的逻辑,被称为通知/增强,比如拓展日志功能,日志功能被称为通知/增强;

     

            前置通知:在方法之前执行
            后置通知:在方法之后执行
            异常通知:方法出现异常
            最终通知:在后置之后执行
            环绕通知:在方法之前和之后执行

      ●  Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field;

      ●  Target(目标对象):代理的目标对象;

      ●  Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程(spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入);

      ●  Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。

      ●  Aspect:切面,将增强应用到具体方法上的过程称为切面(把增强用到切入点过程)
      ●  Joinpoint:连接点,类里面可以被增强的方法,被称为连接点

    1.7 编写切面类

    package com.Kevin.aop;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.context.annotation.Bean;
    
    /**
     * 使用注解方式进行AOP操作
     * 增强类
     * @author Kevin
     *
     */
    
    @Aspect
    public class StrBook {
        
        //在方法上使用注解完成增强配置
        @Before(value="execution(* com.Kevin.aop.Book.*(..))")
        public void add(){
            System.out.println("Before Strength---");
        }
    
    }

    1.8 配置切面

    <bean id="strBook" class="com.Kevin.aop.StrBook"></bean>

    二、Spring的JDBC模版

    2.1 Spring 提供了很多持久层技术的模板类简化编程

    2.2 引入开发相关的包

    2.3 创建一个测试类

    package com.Kevin.jdbc;
    
    import org.junit.Test;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    
    /**
     * 使用jdbcTemplate模版操作数据库
     * @author Kevin
     *
     */
    public class JdbcTemplateDemo1 {
        //添加操作
        @Test
        public void add(){
            //设置数据库信息
            DriverManagerDataSource dataSource=new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///springday3");
            dataSource.setUsername("root");
            dataSource.setPassword("admin");
            
            //创建jdbcTemplate对象,设置数据源
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
            
            //调用jdbcTemplate对象里的方法实现操作
            //创建sql语句
            String sql="insert into user values(?,?)";
            int rows=jdbcTemplate.update(sql,"Kevin","admin");
            System.out.println(rows);
        }
    }    

    三、将连接池交给Spring管理

    3.1 Spring的c3p0连接池配置

    【引入相应的jar包】

    【编写c3p0配置文件】

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 注入属性 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql:///springday3"></property>
            <property name="user" value="root"></property>
            <property name="password" value="admin"></property>
        </bean>
    
        <!-- 创建jdbcTemplate对象 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!-- 把dataSource传递到模版对象里 -->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
    </beans>

    3.2 将数据库连接信息配置到属性文件中

    【定义属性文件】

    //设置数据库信息
            DriverManagerDataSource dataSource=new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///springday3");
            dataSource.setUsername("root");
            dataSource.setPassword("admin");

    四、JDBC模版的CRUD操作

    【添加操作】

        //添加操作
        @Test
        public void add(){
            //设置数据库信息
            DriverManagerDataSource dataSource=new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///springday3");
            dataSource.setUsername("root");
            dataSource.setPassword("admin");
            
            //创建jdbcTemplate对象,设置数据源
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
            
            //调用jdbcTemplate对象里的方法实现操作
            //创建sql语句
            String sql="insert into user values(?,?)";
            int rows=jdbcTemplate.update(sql,"Kevin","admin");
            System.out.println(rows);
        }

    【修改操作】

        //修改操作
        @Test
        public void update(){
            //设置数据库信息
            DriverManagerDataSource dataSource=new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///springday3");
            dataSource.setUsername("root");
            dataSource.setPassword("admin");
            
            //创建jdbcTemplate对象,设置数据源
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
            
            //调用jdbcTemplate对象里的方法实现操作
            //创建sql语句
            String sql="update user set password=? where username=?";
            int rows=jdbcTemplate.update(sql,"666","Kevin");
            System.out.println(rows);
            
            
        }

    【删除操作】

    //删除操作
        @Test
        public void delete(){
            //设置数据库信息
            DriverManagerDataSource dataSource=new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///springday3");
            dataSource.setUsername("root");
            dataSource.setPassword("admin");
            
            //创建jdbcTemplate对象,设置数据源
            JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
            
            //调用jdbcTemplate对象里的方法实现操作
            //创建sql语句
            String sql="delete from user where username=?";
            jdbcTemplate.update(sql,"Kevin");
        }

    五、事务回顾

    5.1 什么是事务

      事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。

    5.2 事务特性

     ● 原子性(Atomicity)操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。

    eg:拿转账来说,假设用户A和用户B两者的钱加起来一共是20000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是20000,这就是事务的一致性。

      ● 一致性(Consistency)事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。

      ● 隔离性(Isolation)隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

                  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

      ● 持久性(Durability)当事务正确完成后,它对于数据的改变是永久性的。

    5.3 如果不考虑隔离性而引发的问题

      ● 脏读 :一个事务读到了另一个事务的未提交的数据。

      ● 不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致。

      ● 虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致。

    5.4 解决读问题:设置事务隔离级别

      事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现脏读不可重复读幻读。下面通过事例一一阐述它们的概念与联系。

    Read uncommitted(最低级别,任何情况都无法保证。)

    读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

    eg:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

    Analyse:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。

    那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。 

     

    Read committed(可避免脏读的发生。)

    读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

    eg:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

    Analyse:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

    那怎么解决可能的不可重复读问题?Repeatable read !

     

    Repeatable read(可避免脏读、不可重复读的发生。)

    重复读,就是在开始读取数据(事务开启)时,不再允许修改操作

    eg:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

    Analyse:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

    什么时候会出现幻读?

    eg:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。

    那怎么解决幻读问题?Serializable!

     

    Serializable(可避免脏读、不可重复读、幻读的发生。) 序列化

    Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

    Tips:大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。

        Mysql的默认隔离级别是Repeatable read。

    Tips:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。

    Tips:设置数据库的隔离级别一定要是在开启事务之前。

       有关事务的详情可查阅什么是事务?事务的四个特性以及事务的隔离级别

    五、Spring进行事务管理一组API

    5.1 PlatformTransactionManager:平台事务管理器

    真正管理事务的对象:

      ● JDBC 或 iBatis 进行持久化数据时使用  org.springframework.jdbc.datasource.DataSourceTransactionManager  

      ● Hibernate 版本进行持久化数据时使用  org.springframework.orm.hibernate3.HibernateTransactionManager 

    5.2 TransactionDefinition:事务定义信息

    事务定义信息:

      ● 隔离级别

      ● 传播行为

      ● 超时信息

      ● 是否只读

    5.3 事务的传播行为

    PROPAGION_XXX :事务的传播行为

    ● 保证同一个事务中

      PROPAGATION_REQUIRED:支持当前事务,如果不存在 就新建一个(默认)

      PROPAGATION_SUPPORTS :支持当前事务,如果不存在,就不使用事务

      PROPAGATION_MANDATORY :支持当前事务,如果不存在,抛出异常

    ● 保证没有在同一个事务中

      PROPAGATION_REQUIRES_NEW:如果有事务存在,挂起当前事务,创建一个新的事务

      PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果有事务存在,挂起当前事务

      PROPAGATION_NEVER :以非事务方式运行,如果有事务存在,抛出异常

      PROPAGATION_NESTED:如果当前事务存在,则嵌套事务执行

    六、案例:搭建一个转账环境

    6.1 创建业务层和DAO类

    package com.Kevin.dao;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class OrdersDao {
    
        //注入jdbcTemplate
        private JdbcTemplate jdbcTemplate;
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
        
        //少钱方法
        public void lessmoney(){
            String sql="update account set salary=salary+? where username=?";
            jdbcTemplate.update(sql,"-1000","Ryan");
            
        }
        
        //多钱方法
        public void moremoney(){
            String sql="update account set salary=salary+? where username=?";
            jdbcTemplate.update(sql,"1000","Kevin");
            
        }
    
    }
    package com.Kevin.service;
    
    import com.Kevin.dao.OrdersDao;
    
    public class OrdersService {
        
        private OrdersDao ordersDao;
    
        public void setOrdersDao(OrdersDao ordersDao) {
            this.ordersDao = ordersDao;
        }
        
        //调用dao方法
        //业务逻辑层,编写转账业务
        public void accountMoney(){
            ordersDao.lessmoney();
            ordersDao.moremoney();
        }
        
        
    
    }

    6.2 配置业务层和DAO

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-4.2.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd 
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
    
        <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 注入属性 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql:///springday3"></property>
            <property name="user" value="root"></property>
            <property name="password" value="admin"></property>
        </bean>
    
        <!-- 第一步:配置事务管理器 -->
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!-- 第二步:配置事务增强 -->
        <tx:advice id="txadvice" transaction-manager="transactionManager">
            <!-- 设置进行事务操作的方法匹配原则 -->
            <tx:attributes>
                <tx:method name="account*" propagation="REQUIRED" />
            </tx:attributes>
        </tx:advice>
        
        <!-- 第三步:配置切面 -->
        <aop:config>
            <!-- 切入点 -->
            <aop:pointcut expression="execution(* com.Kevin.service.OrdersService.*(..))" id="pointcut1"/>
            <!-- 切面 -->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
        </aop:config>
    
        <bean id="ordersService" class="com.Kevin.service.OrdersService">
            <property name="ordersDao" ref="ordersDao"></property>
        </bean>
    
        <bean id="ordersDao" class="com.Kevin.dao.OrdersDao">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
    </beans>

    6.3 编写测试类

    package com.Kevin.service;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestService {
        
        @Test
        public void testService(){
            ApplicationContext context=new ClassPathXmlApplicationContext("beans1.xml");
            int i=1/0;
            OrdersService service=(OrdersService) context.getBean("ordersService");
            service.accountMoney();
        }
        
        
    
    }

    七、Spring声明事物的注解方式

    7.1 引入jar包

    7.2 配置事务管理器并开启事务注解

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-4.2.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd 
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
    
        <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 注入属性 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql:///springday3"></property>
            <property name="user" value="root"></property>
            <property name="password" value="admin"></property>
        </bean>
    
        <!-- 第一步:配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        <!-- 开启事务注解 -->
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
        <bean id="ordersService" class="com.Kevin.service.OrdersService">
            <property name="ordersDao" ref="ordersDao"></property>
        </bean>
    
        <bean id="ordersDao" class="com.Kevin.dao.OrdersDao">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
    </beans>

    7.3 在使用事务的类上添加一个注解:@Transactional

    package com.Kevin.service;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.transaction.annotation.Transactional;
    
    @Transactional
    public class TestService {
        
        @Test
        public void testService(){
            ApplicationContext context=new ClassPathXmlApplicationContext("beans1.xml");
            OrdersService service=(OrdersService) context.getBean("ordersService");
            service.accountMoney();
        }
        
        
    
    }
  • 相关阅读:
    [Reproduced]BIOS -- Basic Input and Output System
    What is CSM mode?
    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2 In TextInputLayout
    What is “passive data structure” in Android/Java?
    Android Studio 手动配置 Gradle
    ScrollView内嵌ListView,ListView显示不全及滑动冲突的问题
    Android安全开发之Provider组件安全
    Android permission and uses-permission
    PriorityBlockingQueue(带优先级的阻塞队列)
    Lesson: Generics (Updated)
  • 原文地址:https://www.cnblogs.com/Kevin-ZhangCG/p/9073524.html
Copyright © 2011-2022 走看看