zoukankan      html  css  js  c++  java
  • Springday03

    使用注解实现IoC以及DI依赖注入

    在配置文件中开启包扫描机制

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
        <!--开启包扫描-->
        <context:component-scan base-package="com.csi" />
    </beans>

     注解实现IoC

    • @Component:将当前的组件,以纯组件的形式加载到IoC容器
    • @Reponsitory:将当前组件,以dao形式加载到IoC容器中
    • @Service:将当前组件,以service形式加载到IoC容器中
    • @Controller:将当前组件,以controller形式加载到IoC容器中

    使用以上注解时,能够给每一个组件进行重命名。默认情况下,以首字母小写为bean的id,存储到IoC容器中。

    使用Autowried或者是Resource来完成DI依赖注入

    @Autowired:按照类型实现自动装配。也就是意味着在容器中必须拥有此类型的bean。如果出现了多个要注入的类型,此时,IoC容器会不知道该注入哪个依赖,这时可以通过@Qualifier("bean-id")来指明要注入具体哪个bean。

    @RunWith(SpringJUnit4ClassRunner.class)
    // 使用注解形式加载spring配置文件->applicationContext.xml
    @ContextConfiguration({"classpath:spring/applicationContext.xml"})
    public class TestSpring {
    
        @Autowired
        @Qualifier("userServiceImpl")
        private UserService userService ;
    
        @Test
        public void test1() {
    
            userService.save(new UserInfo()) ;
    在
        }
    }

    @Resource:按照名称装配(bean的id)。在Spring中,加入注解后,会将对应类型的名称的首字母小写,存储到IoC容器中,Resource通过name在IoC容器中进行匹配。

       @Resource(name = "userServiceImpl")
       private UserService userService ;

    使用annotation注解形式实现AOP

    自定义一个全注解的AOP类

    @Aspect
    public class TransactionManager {
    
        /**
         * 定义连接点
         */
        @Pointcut("execution(* com.csi.service..*.*(..))")
        public void pointcut(){
    
        }
    
        @Before("pointcut()")
        //前置
        public void before(JoinPoint joinPoint) {
            System.out.println("前置");
        }
    
        @AfterReturning(value = "pointcut()",returning = "result")
        //后置
        public void afterReturning(JoinPoint joinPoint,Object result) {
            System.out.println("后置");
        }
    
        @AfterThrowing(value = "pointcut()",throwing = "e")
        //异常
        public void afterThrowing(JoinPoint joinPoint,RuntimeException e) {
            System.out.println("异常");
        }
    
        
        @After(value = "pointcut()")
        //最终
        public void after(JoinPoint joinPoint) {
            System.out.println("最终");
        }
    
        @Around(value = "pointcut()")
        //环绕
        public void around(ProceedingJoinPoint pjp) {
            System.out.println("环绕前置");
            try {
                System.out.println("环绕");
                Object result = pjp.proceed() ;
                System.out.println("提交事务");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("回滚事务");
            } finally {
                System.out.println("关闭资源");
            }
            System.out.println("环绕后置");
        }
    
    }

    在配置文件里,要开启自动代理,同时要告诉容器哪一个类是增强类。

    <!--开启自动代理(Annotataion)-->
    <aop:aspectj-autoproxy />
    <!--通知Spring容器,哪一个类是AOP的增强类-->
    <bean id="transactionManager" class="com.csi.aop.TransactionManager" />

    Spring整合MyBatis

    Spring事务管理

    事务回顾

    @Override
        public void transform() {
        
            String sql = "UPDATE table SET money = money - 500 WHERE userId = 1" ;
            update(sql);
            int num = 3 / 0 ;   // 抛出异常信息
            sql = "UPDATE table SET money = money + 500 WHERE userId = 2" ;
            update(sql) ;
         
        }

     当程序执行3/0会出现异常,导致程序会结束运行,由于前面的update方法已经执行,导致最终总的钱数发生了变化!

    事务四大特性(acid)

    • 原子性(atomicity):事务是不可再分割的最小逻辑单元,一旦执行了,那么最终的结果不会因为出现各种问题而导致数据不统一。  通俗来说:一个事务中的操作,要么都成功,要么都失败。
    • 一致性(consistency):事务执行前以及执行后,最终结果不应该发生变化。  通俗来说:一个事务必须使数据库从一个一致性状态转换到另一个一致性状态。
    • 隔离性(isolation):事务之间应该保持一定的隔离性。   防止脏读、幻读、不可重复读。
    • 持久性(durability):事务一旦提交了,就无法再次回退了。

    事务可能出现的问题

    脏读:读到了没有提交的另一个事务。

    张三开启了一个事务,需要进行转账,此时,李四读到了张三未提交的事务中的金额值,并进了修改,导致最后一致性出问题。

    幻读:读到了已经提交的数据,数据可能新增了,也可能减少了。主要是针对于数据的增加及删除操作。

    张三准备打印流水,在查询后,发现一共30条数据,但是打印后产生了31条数据,导致其感觉出现了幻觉。

    不可重复读:读到了已经提交的数据,但是数据的内容发生了变化。

    张三读取了一条数据,结果是30,但是打印之后,结果变成了28.

    针对于以上的可能出现的问题,数据库进行隔离机制的设计

     

     Oracle的默认隔离级别是已提交读。MySQL默认的是可重复读。

    Spring的事务传播机制

    https://blog.csdn.net/x_h_xx/article/details/106388440

    如果在一个类中,所有的方法上都需要设计对应事务支持方式,那么,如果A方法调用了B方法,此时如何设计?

    1) REQUIRED(默认属性) 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。

    2) MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。

    3) NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。

    4) NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

    5) REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。

    6) SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。

    7) NESTED 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

    PROPAGATION_NESTED 与 PROPAGATION_REQUIRES_NEW的区别: 它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。

    使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA 事务管理器的支持。 使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。

    全XML及半Annotation配置方式

    DataSource、SqlSessionFactoryBean、MapperScan、TransactionManager

    配置数据源

    业界中包括很多非常著名的数据源,例如C3P0、DBCP、Hikari等,而Druid作为alibaba中非常强大的数据连接池,由于其较强的性能及可监控性,也是受到了业界的追捧。

    首先导入坐标

            <!--数据连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>

    由于应用到了MyBatis及数据库,所以一并导入坐标

            <!--mybatis包-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
    
            <!--mybatis-spring整合包-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>2.0.5</version>
            </dependency>
    
            <!--mysql的驱动包-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.15</version>
            </dependency>

    在xml添加配置

        <!--读取配置文件-->
        <context:property-placeholder location="classpath:jdbc.properties" />
    
        <!--配置数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
            <property name="url" value="${mysql_jdbc_url}" />
            <property name="username" value="${mysql_jdbc_user}" />
            <property name="password" value="${mysql_jdbc_password}" />
        </bean>

    jdbc.properties

    #####MySQL数据源配置####
    mysql_jdbc_url=jdbc:mysql://192.168.20.251:3306/test?serverTimezone=Asia/Shanghai
    mysql_jdbc_className=com.mysql.jdbc.Driver
    mysql_jdbc_user=root
    mysql_jdbc_password=root123
    maxActive=80

    整合MyBatis

        <!--完成MyBatis以及Spring的整合-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!--将数据源配置给mybatis-->
            <property name="dataSource" ref="dataSource" />
            <!--配置MyBatis加载的对象的别名:默认情况下,将类名的首字母小写-->
            <property name="typeAliasesPackage" value="com.csi.domain" />
        </bean>
    
        <!--配置映射的接口-->
        <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.csi.dao" />
        </bean>

    整合事务管理及传播机制

        <!--事务配置-->
        <!--1.配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <!--配置增强及相关的一些功能-->
        <tx:advice id="txAdvice">
            <tx:attributes>
                <!--配置切入点。*:代表所有的方法,默认事务传播机制为required,readonly是false值-->
                <tx:method name="*"/>
                <!--根据方法名称,只要find开头的方法全部进行拦截,并且进行事务增强,Supports代表着根据调用者的事务决定自身的事务-->
                <tx:method name="find*" read-only="true" propagation="SUPPORTS" />
            </tx:attributes>
        </tx:advice>
    
        <!--配置切面-->
        <aop:config>
            <aop:pointcut id="pointcut" expression="execution(* com.csi.service..*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
        </aop:config>

    至此,Spring及MyBatis整合完毕

    半XML及半Annotation配置方式

    该种方式,利用Spring的@Transactional实现,在Transactional注解中的配置方式

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
        @AliasFor("transactionManager")  // 获取事务名称
        String value() default "";
    
        @AliasFor("value")
        String transactionManager() default "";
    
        Propagation propagation() default Propagation.REQUIRED; //事务传播机制
    
        Isolation isolation() default Isolation.DEFAULT; //事务隔离级别,默认为数据库设定
    
        int timeout() default -1;  // 超时时长,-1代表永不超时。
     
        boolean readOnly() default false;  //是否为只读
    
        Class<? extends Throwable>[] rollbackFor() default {}; //遇到异常就回滚
    
        String[] rollbackForClassName() default {}; //设置遇到那些类回滚
    
        Class<? extends Throwable>[] noRollbackFor() default {}; // 遇到哪些异常不回滚
    
        String[] noRollbackForClassName() default {};
    }

    在核心配置文件中,增加TransactionManager事务管理器

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

    之后开启事务注解支持

    <tx:annotation-driven/>

    在业务逻辑层添加事务支持

    @Service
    @Transactional
    public class UserInfoServiceImpl implements UserInfoService {
    
        @Autowired
        private UserInfoDao userInfoDao ;
    
    
        @Override
        public void save(UserInfo userInfo) {
            userInfoDao.save(userInfo) ;
        }
    
    
        @Override
        public List<UserInfo> list(int grade_id) {
            return userInfoDao.list(grade_id);
        }
    }

    全Annotation配置方式

    核心配置SpringConfig.java

    @Configuration
    @Import({DataSourceConfig.class,MybatisConfig.class,TransactionManagerConfig.class})
    @ComponentScan("com.csi")
    @EnableAspectJAutoProxy
    @EnableTransactionManagement
    public class SpringConfig {
    }

    数据源配置DataSourceConfig.java

    @PropertySource({"jdbc.properties"})
    public class DataSourceConfig {
    
        @Value("${mysql_jdbc_url}")
        private String url;
    
        @Value("${mysql_jdbc_user}")
        private String user;
    
        @Value("${mysql_jdbc_password}")
        private String password;
    
        @Bean
        public DruidDataSource getDataSource(){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setUrl(url);
            dataSource.setUsername(user);
            dataSource.setPassword(password);
            return dataSource;
        }
    }

    Mybatis配置MybatisConfig.java

    public class MybatisConfig {
    
        /**
         * 构建factoryBean对象
         * @param dataSource 数据源
         * @return factoryBean对象
         */
        @Bean
        public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setTypeAliasesPackage("com.csi.domain");
            return sessionFactoryBean;
        }
    
        /**
         * 构件mapper扫描对象
         * @return mapper扫描对象
         */
        @Bean
        public MapperScannerConfigurer getMapperScanner(){
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setBasePackage("com.csi.dao");
            return mapperScannerConfigurer;
        }
    }

    事务管理器配置TransactionManagerConfig.java

    public class TransactionManagerConfig {
    
        @Bean
        public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
            DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
    
            dataSourceTransactionManager.setDataSource(dataSource);
    
            return dataSourceTransactionManager;
        }
    }
  • 相关阅读:
    云中树莓派(5):利用 AWS IoT Greengrass 进行 IoT 边缘计算
    乐观锁 与 悲观锁 来解决数据库并发问题
    Python二维数组构造
    一次问题追查----短字符串签名算法引发的bug
    C++ assert 断言使用
    并查集(Union-Find)算法
    linux shell grep/awk/sed 匹配tab
    C++ 变量默认初始值不确定(代码测试)
    linux 查看机器内存方法 (free命令)
    html table奇偶行颜色设置 (CSS选择器)
  • 原文地址:https://www.cnblogs.com/heureuxl/p/13887962.html
Copyright © 2011-2022 走看看