Spring的JdbcTemplate、Aop及小结(个人笔记)

为了完全实现Annotation的方式开发,将bean.xml取代,首先需要有可以扫描全局的注解

    @ComponentScan(basePackages = {"com.kali"})还要让spring知道你的配置类是哪个
    这就需要第二个注解:@Configuration,对于runner和dataSource在xml中采用的时Ioc的
    方式,所以观察其结构

    @Bean用于把当前方法的返回值作为bean对象存入spring的ioc容器管理。
        当我们使用注解配置方法时,如果方法有参数,spring框架会自动到容器中查找
    看有没有可用的bean对象。查找方式和@Autowired的作用一样

    @Configuration不是什么时候都可以不写的,只有当作为AnnotationConfigApplicationContext()
    的参数时才可以不写,如果AnnotationConfigApplicationContext的参数中并列写上两个配置类的
    Class不添加@Configuration、依然可以实现,那么就成了兄弟关系,其实SpringConfiguration
    是想作为主配置的

    @Import用于导入其它配置类的字节码,当使用@Import注解时,有@Import注解的类就是父配置类,
    导入的则是子配置类,显然父子的配置关系是合理的。

    @PropertySource:
        为了解决读取配置文件,并通过@Value为属性注入
    @PropertySource(value = {"classpath:jdbcConfig.properties"})
        这个注解用于指定properties文件的位置
        value属性指定文件的位置,关键字classpath表示类路径

    小结:
        基于xml的开发方式和基于annotation的方式,怎么方便怎么来,有时基于全注解的方式开发反而增加了工作量
    xml和annotation结合的方式也挺好

    spring是如何选择不同的数据源的:
        这个问题归根结底是被注解修饰的方法如果有参数,那么参数的对的对象是如何选择具有多个
        匹配情况下的选择。

        使用@Qualifier来解决,当方法参数出现多个符合注入的匹配情况时,使用这个注解来指定在冲突情况下选择的注入
        对象。例如不同的数据源的使用,出现无法精确匹配时就可以使用此注解

JDBC配置文件最好是这样的格式:
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm
    jdbc.username=root
    jdbc.password=super
    我尝试取掉前面的jdbc.前缀,结果数据库一直延迟连接,最后失败,只是报了超时

Spring整合Junit配置
    1.导入Spring整合Junit的坐标
    2.使用Junit提供的一个注解将Junit的main方法替换成Spring提供的
            @RunWith(SpringJUnit4ClassRunner.class)
    3.告知spring运行器,spring的ioc创建是基于xml还是注解的,说明位置
            基于xml:@ContextConfiguration(classes = {SpringBeanConfiguration.class})
                classpath代表是类路径下
            基于annotation:@ContextConfiguration(locations = {"classpath:bean.xml"})
                locations属性代表位置
                classes属性代表配置类位置

Spring的事务管理
    public void transfer(String sourceName, String targetName, double money) {
            /*
             * 1.查询转出账户
             * 2.查询转入账户
             * 3.转出账户减
             * 4.转入账户加
             * 5.更新转出账户
             * 6.更新转入账户
             */
            User source = userDao.findByName(sourceName);//获取连接
            User target = userDao.findByName(targetName);//获取连接
            source.setMoney(source.getMoney() - money);
            target.setMoney(target.getMoney() + money);
            userDao.updateUser(source);//获取连接
            /*int i = 10/0;*/
            userDao.updateUser(target);//获取连接
        }

        每个Connection都有自己的独立事务,为了让这几个独立的事务组合成一个事务,使用
        ThreadLocal把Connection和当前线程绑定,使一个线程中只有一个能控制的事务对象

        事务管理回到业务层service
                1.转账过程:查询转出账户、转入账户、转出账户余额减少、转入账户余额增加,更新转出、
            更新转入账户这几步操作。如果在两个更新操作之间发生异常可能导致余额不翼而飞,多以
            要对事务进行控制。
                2.分析原因:转账过程中总共由四次连接,而每一次数据库连接都有其单独的事务控制,所以这是
            四个单独的原子控制组成的一个逻辑操作,那么要将四个单独的事务控制在一个连接中解决就可以
            保证事务的原子性。
                3.如何操作:将一个链接绑定在一个线程上,那么这个线程的所有操作就是一个连接在操作,也就能
            保证事务

            小结:在事务控制权的转变过程中,我们将数据源交给了ConnectionUtils来管理。dao层执行时先到工具类
            中当前线程本地尝试获取连接,如果有连接则说明上一个执行的方法和将要执行的方法属于同一个事务控制下的,
            否则,则说明是第一次操作。然后由事务控制类进行事务控制。

SpringAop
    基于注解的Aop配置,识别expression需要AspectJ Jar包支持
            <aop:aspectj-autoproxy/>开启Aop
            @EnableAspectJAutoProxy注解开启Aop
            @Aspect切面
            @Pointcut("execution(* com.kali.service.impl.*.*(..))")
            private void point(){} //在普通方法上声明全局表达式
            @Before("point()")
            @AfterReturning("point()")
            @AfterThrowing("point()")
            @After("point()")
            @Around("point()")

    Aspect:切入点和通知的结合就是切面,通知是切点前后的操作

    SpringAop的配置:
            AspectJ是解析表达式的

            join point指的是那些拦截的点,指的是方法,spring只支持方法类型的连接点
            point cut指对哪些join point进行拦截的定义

            1.包通知交给spring管理
            2.使用aop:config标签表明aop的配置
            3.使用aop:aspect标签配置切面
                id 给切面一个唯一标识
                ref 指定通知类bean的id
            4.在aop:aspect标签内使用对应标签配置通知类型
                aop:before
                aop:after
                aop:around
                    pointcut = "execution()"将通知和切入点关联
            5.execution表达式的写法:
                修饰符 返回值 全限定路径+方法名
                全局通配写法: * *..*.*(..)
                    表达式书写规则:
                        访问修饰符可以省略
                        包名 * 匹配任意包,但有几级就得有几个*
                        可以写 *..代表当前包及子包
                            (..)代表有无参数都可匹配
                            (*)代表有参数
                        实际开发中表达式的写法:* com.kali.service.impl.*.*(..)
                <aop:before method="pre" pointcut="execution(* com.kali.service.impl.*.*(..))"/>
                <aop:after-returning method="afterReturn" pointcut="execution(* com.kali.service.impl.*.*(..))"/>
                <aop:after-throwing method="afterThrowing" pointcut="execution(* com.kali.service.impl.*.*(..))"/>
                <aop:after method="after" pointcut="execution(* com.kali.service.impl.*.*(..))"/>
                <aop:around method="around" pointcut-ref="pc"/>
                前置通知:在切点前执行
                后置通知:在切点正常执行后执行
                异常通知:在切点执行中发生异常后执行
                最终通知:无论切点是否正常执行都会执行
                环绕通知:当我们配置了环绕通知却没有执行切入点方法,只执行了通知方法
                    分析原因:再写到那个太代理的时候对代理方法做了增强。
                通过对比动态代理的环绕通知,发现动态代理的环绕通知中有明确的切点方法调用。
                我们的却没有。
                    解决方法:
                        spring提供了一个ProceedingJoinPoint接口,提供类一个proceed方法
                    就相当于明确调用切入点方法,该接口可作为环绕通知方法的参数,执行时
                    框架为我们提供实现类使用
            小结:前置通知在切点前执行,后置通知在切点正确执行后执行异常通知在切点发生异常
            时执行最终通知无论方法是否正确执行都会执行。环绕通知可以将四种通知融合形成完整的
            如动态代理的环绕通知。

    尤其着重@Around
        【动态代理本身就是一个环绕通知:有前置、后置、异常、最终、切点】
        @Around("point()")
            public Object around(ProceedingJoinPoint joinPoint){
                Object result = null;
                try {
                    pre();
                    //明确调用业务层方法(aop标签中配置的切入点方法)
                    result = joinPoint.proceed(joinPoint.getArgs());
                    afterReturn();
                } catch (Throwable throwable) {
                    afterThrowing();
                    throwable.printStackTrace();
                }finally {
                    after();
                }
                return result;
            }
    切面:通知+切点

Spring的JdbcTemplate类似DbUtils
    1.准备数据源 负责与数据库建立连接
    使用spring提供的数据源DriverManagerDataSource
    2.创建JdbcTemplate
    JdbcTemplate jt = new JdbcTemplate();
    设置数据源给jt,也可传参
    jt.setDataSource(ds);
    3.对于有结果集的返回用RowMapper<Object>接收,它是一个接口,封装如何将单一的
    对象封装,装填到集合中,可自己实现,但没必要。使用spring提供的
    new BeanPropertyRowMapper<>(User.class)这样的方式使用即可。
    4.【注意】对于查询返回一行一列,即聚合函数型的,只能使用queryForObject,如下:
        Integer count = jt.queryForObject("select count(*) from user1 where money >= ?", int.class,5000);

    **JdbcDaoSupport**
---------------------------------------------------------------------
Spring基于Aop的事务控制
    Spring的事务必须基于Aop么
    思考:使用template的事务,使用mysql的事务?为什么使用Aop,不使用
    的情况下通过什么来实现事务控制?可以不使用Aop带需要大量代码
在没有使用spring的jdbc时对事务的控制使用
    <<试着重写基于mysql、c3p0连接池的转账事务控制>>
        我尝试拿到spring的JdbcTemplate的数据源的连接但是拿不到,所以不能将连接的
    事务控制掌握在自己手里。试着创建一个环绕通知的类,

Spring基于Xml、Annotation的事务控制
    Spring可以使用xml、Annotation、编程式来实现事务

1.Spring中基于xml的声明式事务
    开启spring对注解事务的支持<tx:annotation-driven/>
    开启对Aop的支持<aop:aspectj-autoproxy/>
            1.配置事务管理器
            2.配置事务的通知
            3.配置切点表达式
            4.建立事务通知与切点之间的关系
            5.配置事务的属性
                isolation指定事务的隔离级别,默认是default表示使用数据库的默认隔离级别
                propagation指定事物的传播行为,默认是required表示一定会有事务,增删改的选择,查询可使用supports
                read-only指定事务只读,只有查询才可以设置为true,默认为false表示读写
                timeout指定事务超时时间,默认-1表示永不超时,如果指定以s为单位
                rollback-for指定一个异常产生时事务回滚,其他异常不会滚,没有默认值表示任意异常都回滚
                no-rollback-for指定一个异常,当产生该异常时,事务不回滚,其他异常时事务回滚,没有默认值表示任何异常都回滚

2.Spring中基于Annotation的声明式事务
    1.首先开启spring对注解事务的支持@EnableTransactionManagement
    2.全局的设置,对于查询这样可以配置@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
    如果有读写操作的需要单独配置@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
    3.不再需要开启aop的注解需要和@Aspect的配置

数据源:C3p0,Spring的DriverManageDataSource
    数据源可以创建连接池,存储连接
DbUtils,Mybatis,Hibernate,JdbcTemplate是对jdbc的封装

证明:使用c3p0作为数据源和DbUtils操作数据库的事务控制只能采用spring的环绕通知来解决,而不能像spring的JdbcTemplate
那样使用Spring提供的DataSourceTransactionManager来管理事务。根本原因在于通过JdbcTemplate拿到的数据库连接,不能将AutoCommit设置为false,因为我改不了,在测试时AutoCommit始终获取到的是true。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值