美文网首页springspring framework
Spring框架学习1:Spring 集成 MyBatis、Sp

Spring框架学习1:Spring 集成 MyBatis、Sp

作者: 苦难_69e0 | 来源:发表于2021-03-18 12:41 被阅读0次

    Spring 集成 MyBatis

    将 MyBatis 与 Spring 进行整合,主要解决的问题就是将 SqlSessionFactory 对象交由 Spring来管理。所以,该整合,只需要将 SqlSessionFactory 的对象生成器 SqlSessionFactoryBean 注册在 Spring 容器中,再将其注入给 Dao 的实现类即可完成整合。

    实现 Spring 与 MyBatis 的整合常用的方式:扫描的 Mapper 动态代理

    Spring 像插线板一样,mybatis 框架是插头,可以容易的组合到一起。插线板 spring 插 上 mybatis,两个框架就是一个整体。

    MySQL 创建数据库 springdb,新建表 Student

    image.png

    maven 依赖 pom.xml

    <dependency> 
        <groupId>junit</groupId> 
        <artifactId>junit</artifactId>
         <version>4.11</version>
         <scope>test</scope>
    </dependency>
    
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-context</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId> 
        <artifactId>spring-tx</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency> 
        <groupId>org.springframework</groupId>
         <artifactId>spring-jdbc</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
         <groupId>org.mybatis</groupId> 
        <artifactId>mybatis</artifactId>
         <version>3.5.1</version>
    </dependency>
    
    <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis-spring</artifactId> 
        <version>1.3.1</version>
    </dependency>
    
    <dependency> 
        <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId> 
        <version>5.1.9</version>
    </dependency>
    
    <dependency> 
        <groupId>com.alibaba</groupId> 
        <artifactId>druid</artifactId> 
        <version>1.1.12</version>
    </dependency>
    

    插件:

     <build>
         <resources>
             <resource>
                 <directory>src/main/java</directory><!--所在的目录-->
                 <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                     <include>**/*.properties</include>
                     <include>**/*.xml</include>
                 </includes>
                 <filtering>false</filtering>
             </resource>
        </resources>
    
        <plugins>
             <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.1</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
                 </configuration>
             </plugin>
         </plugins>
     </build>
    

    定义实体类 Student

    image.png

    定义 StudentDao 接口

    image.png

    定义映射文件 mapper

    在 Dao 接口的包中创建 MyBatis 的映射文件 mapper,命名与接口名相同,本例为StudentDao.xml。mapper 中的 namespace 取值也为 Dao 接口的全限定性名。

    image.png

    定义 Service 接口和实现类

    接口定义:


    image.png

    实现类定义:


    image.png

    定义 MyBatis 主配置文件

    在 src 下定义 MyBatis 的主配置文件,命名为 mybatis.xml。
    这里有两点需要注意:
    (1)主配置文件中不再需要数据源的配置了。因为数据源要交给 Spring 容器来管理了。
    (2)这里对 mapper 映射文件的注册,使用<package/>标签,即只需给出 mapper 映射文件所在的包即可。因为 mapper 的名称与 Dao 接口名相同,可以使用这种简单注册方式。这种方式的好处是,若有多个映射文件,这里的配置也是不用改变的。当然,也可使用原来的<resource/>标签方式。

    image.png

    修改 Spring 配置文件

    (1) 数据源的配置(掌握)
    使用 JDBC 模板,首先需要配置好数据源,数据源直接以 Bean 的形式配置在 Spring 配置文件中。根据数据源的不同,其配置方式不同:

    Druid 数据源 DruidDataSource
    Druid 是阿里的开源数据库连接池。是 Java 语言中最好的数据库连接池。Druid 能够提供强大的监控和扩展功能。Druid 与其他数据库连接池的最大区别是提供数据库的

    官网:https://github.com/alibaba/druid
    使用地址:https://github.com/alibaba/druid/wiki/常见问题

    配置连接池:


    image.png

    Spring 配置文件:


    image.png

    (2) 从属性文件读取数据库连接信息
    为了便于维护,可以将数据库连接信息写入到属性文件中,使 Spring 配置文件从中读取数据。
    属性文件名称自定义,但一般都是放在 src 下。

    image.png

    Spring 配置文件从属性文件中读取数据时,需要在<property/>的 value 属性中使用${ },将在属性文件中定义的 key 括起来,以引用指定属性的值。

    image.png

    该属性文件若要被 Spring 配置文件读取,其必须在配置文件中进行注册。使用<context>标签。

    <context:property-placeholder/>方式(掌握)
    该方式要求在 Spring 配置文件头部加入 spring-context.xsd 约束文件

    <context:property-placeholder/>标签中有一个属性 location,用于指定属性文件的位置。

    image.png

    (3) 注册 SqlSessionFactoryBean

    image.png

    (4) 定义 Mapper 扫描配置器 MapperScannerConfigurer
    Mapper 扫描配置器 MapperScannerConfigurer 会自动生成指定的基本包中 mapper 的代理对象。该 Bean 无需设置 id 属性。basePackage 使用分号或逗号设置多个包。

    image.png

    向 Service 注入接口名

    向 Service 注入 Mapper 代理对象时需要注意,由于通过 Mapper 扫描配置器MapperScannerConfigurer 生成的 Mapper 代理对象没有名称,所以在向 Service 注入 Mapper代理时,无法通过名称注入。但可通过接口的简单类名注入,因为生成的是这个 Dao 接口的对象。

    image.png

    Spring 配置文件全部配置

    image.png

    Spring 事务

    Spring 的事务管理

    事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层,即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。
    在 Spring 中通常可以通过以下两种方式来实现对事务的管理:
    (1)使用 Spring 的事务注解管理事务
    (2)使用 AspectJ 的 AOP 配置管理事务

    Spring 事务管理 API

    Spring 的事务管理,主要用到两个事务相关的接口。

    (1) 事务管理器接口(重点)

    事务管理器是 PlatformTransactionManager 接口对象。其主要用于完成事务的提交、回滚,及获取事务的状态信息。

    image.png

    A、常用的两个实现类

    PlatformTransactionManager 接口有两个常用的实现类:
    DataSourceTransactionManager:使用 JDBC 或 MyBatis 进行数据库操作时使用。
    HibernateTransactionManager:使用 Hibernate 进行持久化数据时使用。

    B、 Spring 的回滚方式(理解)

    Spring 事务的默认回滚方式是:发生运行时异常和 error 时回滚,发生受查(编译)异常时提交。不过,对于受查异常,程序员也可以手工设置其回滚方式。

    C、 回顾错误与异常(理解)

    image.png

    Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java 的 throw 语句抛出。

    Error 是程序在运行过程中出现的无法处理的错误,比如 OutOfMemoryError、ThreadDeath、NoSuchMethodError 等。当这些错误发生时,程序是无法处理(捕获或抛出)的,JVM 一般会终止线程。

    程序在编译和运行时出现的另一类错误称之为异常,它是 JVM 通知程序员的一种方式。通过这种方式,让程序员知道已经或可能出现错误,要求程序员对其进行处理。

    异常分为运行时异常与受查异常。

    运行时异常,是 RuntimeException 类或其子类,即只有在运行时才出现的异常。如,NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException 等均属于运行时异常。这些异常由 JVM 抛出,在编译时不要求必须处理(捕获或抛出)。但,只要代码编写足够仔细,程序足够健壮,运行时异常是可以避免的。

    受查异常,也叫编译时异常,即在代码编写时要求必须捕获或抛出的异常,若不处理,则无法通过编译。如 SQLException,ClassNotFoundException,IOException 等都属于受查异常。

    RuntimeException 及其子类以外的异常,均属于受查异常。当然,用户自定义的 Exception的子类,即用户自定义的异常也属受查异常。程序员在定义异常时,只要未明确声明定义的为 RuntimeException 的子类,那么定义的就是受查异常。

    (2) 事务定义接口

    事务定义接口 TransactionDefinition 中定义了事务描述相关的三类常量:事务隔离级别、事务传播行为、事务默认超时时限,及对它们的操作。

    image.png

    A、定义了五个事务隔离级别常量(掌握)

    这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。

    DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。 READ_UNCOMMITTED:读未提交。未解决任何并发问题。
    READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
    REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
    SERIALIZABLE:串行化。不存在并发问题。

    B、 定义了七个事务传播行为常量(掌握)

    所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情况。如,A 事务中的方法 doSome()调用 B 事务中的方法 doOther(),在调用执行期间事务的维护情况,就称为事务传播行为。事务传播行为是加在方法上的。

    事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。

    PROPAGATION_REQUIRED
    PROPAGATION_REQUIRES_NEW
    PROPAGATION_SUPPORTS

    PROPAGATION_MANDATORY
    PROPAGATION_NESTED
    PROPAGATION_NEVER
    PROPAGATION_NOT_SUPPORTED

    a、 PROPAGATION_REQUIRED:

    指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。

    如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther()方法时就是在事务内运行的,则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。

    image.png

    b、PROPAGATION_SUPPORTS

    指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。

    image.png

    c、 PROPAGATION_REQUIRES_NEW

    总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。

    image.png

    C、 定义了默认事务超时时限

    常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限,sql 语句的执行时长。
    注意,事务的超时时限起作用的条件比较多,且超时的时间计算点较复杂。所以,该值一般就使用默认值即可。

    程序举例环境搭建

    举例:购买商品 trans_sale 项目
    本例要实现购买商品,模拟用户下订单,向订单表添加销售记录,从商品表减少库存。

    实现步骤:

    Step0:创建数据库表

    创建两个数据库表 sale , goods
    sale 销售表


    image.png

    goods 商品表


    image.png

    goods 表数据


    image.png

    Step1: maven 依赖 pom.xml

    <dependency> 
        <groupId>junit</groupId> 
        <artifactId>junit</artifactId>
         <version>4.11</version> 
        <scope>test</scope>
    </dependency>
    
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-context</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
         <artifactId>spring-tx</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
         <groupId>org.springframework</groupId> 
        <artifactId>spring-jdbc</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
         <groupId>org.mybatis</groupId> 
        <artifactId>mybatis</artifactId>
         <version>3.5.1</version>
    </dependency>
    
    <dependency> 
        <groupId>org.mybatis</groupId> 
        <artifactId>mybatis-spring</artifactId>
         <version>1.3.1</version>
    </dependency>
    
    <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId> 
        <version>5.1.9</version>
    </dependency>
    
    <dependency> 
        <groupId>com.alibaba</groupId>
         <artifactId>druid</artifactId>
         <version>1.1.12</version>
    </dependency>
    

    插件

    <build>
         <resources>
             <resource>
                 <directory>src/main/java</directory><!--所在的目录-->
                 <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                     <include>**/*.properties</include>
                     <include>**/*.xml</include>
                 </includes>
                 <filtering>false</filtering>
             </resource>
         </resources>
        <plugins>
             <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.1</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
                 </configuration>
             </plugin>
         </plugins>
    </build>
    

    Step2:创建实体类

    创建实体类 Sale 与 Goods


    image.png

    Step3:定义 dao 接口

    定义两个 dao 的接口 SaleDao , GoodsDao


    image.png

    Step4:定义 dao 接口对应的 sql 映射文件

    SaleDao.xml


    image.png

    GoodsDao.xml


    image.png

    Step5:定义异常类

    定义 service 层可能会抛出的异常类 NotEnoughException


    image.png

    Step6:定义 Service 接口

    定义 Service 接口 BuyGoodsService


    image.png

    Step7:定义 service 的实现类

    定义 service 层接口的实现类 BuyGoodsServiceImpl

    1. 类定义


      image.png
    2. Dao 属性


      image.png
    3. Buy 方法


      image.png

    Step8:修改 Spring 配置文件内容

    声明 Mybatis 对象


    image.png

    声明业务层对象


    image.png

    Step9:定义测试类

    定义测试类 MyTest。现在就可以在无事务代理的情况下运行了。


    image.png

    使用 Spring 的事务注解管理事务(掌握)

    通过@Transactional 注解方式,可将事务织入到相应 public 方法中,实现事务管理。

    @Transactional 的所有可选属性如下所示:
    ➢ propagation:用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。
    ➢ isolation:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为Isolation.DEFAULT。
    ➢ readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值为 false。
    ➢ timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为-1,即没有时限。
    ➢ rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    ➢ rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    ➢ noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    ➢ noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。

    需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。
    若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。

    实现注解的事务步骤:
    复制 trans_sale 项目,新项目 trans_sale_annotation

    1. 声明事务管理器


      image.png
    2. 开启注解驱动


      image.png

    transaction-manager:事务管理器 bean 的 id

    1. 业务层 public 方法加入事务属性


      image.png

    使用 AspectJ 的 AOP 配置管理事务(掌握)

    使用 XML 配置事务代理的方式的不足是,每个目标类都需要配置事务代理。当目标类较多,配置文件会变得非常臃肿。

    使用 XML 配置顾问方式可以自动为每个符合切入点表达式的类生成事务代理。其用法很简单,只需将前面代码中关于事务代理的配置删除,再替换为如下内容即可。

    Step1:复制项目
    复制 trans_sale 项目,并重命名为 trans_sal_aspectj。在此基础上修改。

    Step2:maven 依赖 pom.xml

    新加入 aspectj 的依赖坐标

    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-aspects</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    

    Step3:在容器中添加事务管理器


    image.png

    Step4:配置事务通知

    为事务通知设置相关属性。用于指定要将事务以什么方式织入给哪些方法。
    例如,应用到 buy 方法上的事务要求是必须的,且当 buy 方法发生异常后要回滚业务。

    image.png

    Step5:配置增强器

    指定将配置好的事务通知,织入给谁。

    image.png

    Step6:修改测试类

    测试类中要从容器中获取的是目标对象。

    image.png

    Spring 与 Web

    在 Web 项目中使用 Spring 框架,首先要解决在 web 层(这里指 Servlet)中获取到 Spring容器的问题。只要在 web 层获取到了 Spring 容器,便可从容器中获取到 Service 对象。

    Web 项目使用 Spring 的问题(了解)

    举例:springWeb 项目(在 spring-mybatis 基础上修改)

    Step1:新建一个 Maven Project

    类型 maven-archetype-webapp

    Step2: 复制代码,配置文件,jar

    将 spring-mybatis 项目中以下内容复制到当前项目中:
    (1)Service 层、Dao 层全部代码
    (2)配置文件 applicationContext.xml 及 jdbc.properties,mybatis.xml
    (3)pom.xml
    (4)加入 servlet ,jsp 依赖

    在之前原有的 pom.xml 文件中再加入以下的内容:

    <!-- servlet依赖 -->
    <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
         <version>3.1.0</version>
         <scope>provided</scope>
    </dependency>
    
    <!-- jsp依赖 -->
    <dependency> 
         <groupId>javax.servlet.jsp</groupId> 
         <artifactId>jsp-api</artifactId> 
         <version>2.2.1-b03</version> 
         <scope>provided</scope>
    </dependency>
    

    Step3:定义 index 页面

    image.png

    Step4:定义 RegisterServlet(重点代码)

    image.png

    Step5:定义 success 页面

    image.png

    Step6:web.xml 注册 Servlet

    image.png

    Step7:运行结果分析

    当表单提交,跳转到 success.jsp 后,多刷新几次页面,查看后台输出,发现每刷新一次页面,就 new 出一个新的 Spring 容器。即,每提交一次请求,就会创建一个新的 Spring 容器。对于一个应用来说,只需要一个 Spring 容器即可。所以,将 Spring 容器的创建语句放在 Servlet 的 doGet()或 doPost()方法中是有问题的。

    image.png

    此时,可以考虑,将 Spring 容器的创建放在 Servlet 进行初始化时进行,即执行 init()方法时执行。并且,Servlet 还是单例多线程的,即一个业务只有一个 Servlet 实例,所有执行该业务的用户执行的都是这一个 Servlet 实例。这样,Spring 容器就具有了唯一性了。

    但是,Servlet 是一个业务一个 Servlet 实例,即 LoginServlet 只有一个,但还会有StudentServlet、TeacherServlet 等。每个业务都会有一个 Servlet,都会执行自己的 init()方法,也就都会创建一个 Spring 容器了。这样一来,Spring 容器就又不唯一了。

    使用 Spring 的监听器 ContextLoaderListener(掌握)

    举例:springweb-2 项目(在 spring-web 项目基础上修改)

    对于 Web 应用来说,ServletContext 对象是唯一的,一个 Web 应用,只有一个ServletContext 对象,该对象是在 Web 应用装载时初始化的。若将 Spring 容器的创建时机,放在 ServletContext 初始化时,就可以保证 Spring 容器的创建只会执行一次,也就保证了Spring 容器在整个应用中的唯一性。

    当 Spring 容器创建好后,在整个应用的生命周期过程中,Spring 容器应该是随时可以被访问的。即,Spring 容器应具有全局性。而放入 ServletContext 对象的属性,就具有应用的全局性。所以,将创建好的 Spring 容器,以属性的形式放入到ServletContext 的空间中,就保证了 Spring 容器的全局性。

    上述的这些工作,已经被封装在了如下的 Spring 的 Jar 包的相关 API 中:
    spring-web-5.2.5.RELEASE

    Step1:maven 依赖 pom.xml

    <dependency> 
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId> 
        <version>5.2.5.RELEASE</version>
    </dependency>
    

    Step2:注册监听器 ContextLoaderListener

    若要在 ServletContext 初 始 化 时 创 建 Spring 容 器 , 就 需 要 使 用 监 听 器 接 口ServletContextListener 对 ServletContext 进行监听。在 web.xml 中注册该监听器。

    image.png

    Spring 为该监听器接口定义了一个实现类 ContextLoaderListener,完成了两个很重要的工作:创建容器对象,并将容器对象放入到了 ServletContext 的空间中。

    打开 ContextLoaderListener 的源码。看到一共四个方法,两个是构造方法,一个初始化方法,一个销毁方法。

    image.png

    所以,在这四个方法中较重要的方法应该就是 contextInitialized(),context 初始化方法。

    image.png

    跟踪 initWebApplicationContext()方法,可以看到,在其中创建了容器对象。

    image.png

    并且,将创建好的容器对象放入到了 ServletContext 的空间中,key 为一个常量:
    WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。

    image.png

    Step3:指定 Spring 配置文件的位置<context-param>

    ContextLoaderListener 在对 Spring 容器进行创建时,需要加载 Spring 配置文件。其默认的 Spring 配置文件位置与名称为:WEB-INF/applicationContext.xml。但,一般会将该配置文件放置于项目的 classpath 下,即 src 下,所以需要在 web.xml 中对 Spring 配置文件的位置及名称进行指定。

    image.png

    从监听器 ContextLoaderListener 的父类 ContextLoader 的源码中可以看到其要读取的配置文件位置参数名称 contextConfigLocation。

    image.png

    Step4:获取 Spring 容器对象

    在 Servlet 中获取容器对象的常用方式有两种:
    (1) 直接从 ServletContext 中获取

    从对监听器 ContextLoaderListener 的源码分析可知,容器对象在 ServletContext 的中存放的 key 为 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。所以,可以直接通过 ServletContext 的 getAttribute()方法,按照指定的 key 将容器对象获取到。

    image.png

    (2) 通过 WebApplicationContextUtils 获取

    工具类 WebApplicationContextUtils 有一个方法专门用于从 ServletContext 中获取 Spring容器对象:getRequiredWebApplicationContext(ServletContext sc)

    调用 Spring 提供的方法获取容器对象:


    image.png

    查其源码,看其调用关系,就可看到其是从 ServletContext 中读取的属性值,即 Spring容器。

    image.png

    以上两种方式,无论使用哪种获取容器对象,刷新 success 页面后,可看到代码中使用的 Spring 容器均为同一个对象。

    image.png

    总结

    spring全家桶:spring , springmvc ,spring boot , spring cloud

    spring: 出现是在2002左右,解决企业开发的难度。减轻对项目模块之间的管理,类和类之间的管理, 帮助开发人员创建对象,管理对象之间的关系。

    spring核心技术 ioc , aop 。能实现模块之间,类之间的解耦合。

    依赖:class A中使用class B的属性或者方法, 叫做class A依赖class B


    框架怎么学: 框架是一个软件,其它人写好的软件。
    1)知道框架能做什么, mybatis--访问数据库, 对表中的数据执行增删改查。
    2)框架的语法, 框架要完成一个功能,需要一定的步骤支持的,
    3)框架的内部实现, 框架内部怎么做。 原理是什么。
    4)通过学习,可以实现一个框架。

    spring的第一个核心功能 ioc

    IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。
    描述的:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。

    控制: 创建对象,对象的属性赋值,对象之间的关系管理。
    反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。

    正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。

    public static void main(String args[]){
         Student student = new Student(); // 在代码中, 创建对象。--正转。
    }
    

    容器:是一个服务器软件, 一个框架(spring)

    为什么要使用 ioc : 目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。

    java中创建对象有哪些方式:

    1. 构造方法 , new Student()
    2. 反射
    3. 序列化
    4. 克隆
    5. ioc :容器创建对象
    6. 动态代理

    ioc的体现:
    servlet
    1: 创建类继承HttpServelt
    2: 在web.xml 注册servlet , 使用
    <servlet-name> myservlet </servlet-name>
    <servelt-class>com.bjpwernode.controller.MyServlet1</servlet-class>

    1. 没有创建 Servlet对象, 没有 MyServlet myservlet = new MyServlet()

    2. Servlet 是Tomcat服务器它能你创建的。 Tomcat也称为容器
      Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象

    IoC的技术实现 ,
    DI 是ioc的技术实现,
    DI(Dependency Injection) :依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,赋值,查找都由容器内部实现。

    spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。

    spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。

    spring-conetxt 和 spring-webmvc是spring中的两个模块

    spring-context:是ioc功能的,创建对象的。
    spring-webmvc做web开发使用的, 是servlet的升级。
    spring-webmvc中也会用到spring-context中创建对象的功能的。

    junit : 单元测试, 一个工具类库,做测试方法使用的。
    单元:指定的是方法, 一个类中有很多方法,一个方法称为单元。

    使用单元测试
    1.需要加入junit依赖。

          <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    

    2.创建测试作用的类:叫做测试类
    src/test/java目录中创建类

    3.创建测试方法

    1)public 方法
    2)没有返回值 void
    3)方法名称自定义,建议名称是test + 你要测试方法名称
    4)方法没有参数
    5)方法的上面加入 @Test ,这样的方法是可以单独执行的。 不用使用main方法。


    多个配置优势
    1.每个文件的大小比一个文件要小很多。效率高
    2.避免多人竞争带来的冲突。

    如果你的项目有多个模块(相关的功能在一起) ,一个模块一个配置文件。
    学生考勤模块一个配置文件, 张三
    学生成绩一个配置文件, 李四

    多文件的分配方式:

    1. 按功能模块,一个模块一个配置文件
    2. 按类的功能,数据库相关的配置一个文件配置文件, 做事务的功能一个配置文件, 做service功能的一个配置文件等

    基于注解的di: 通过注解完成java对象创建,属性赋值。

    使用注解的步骤:
    1.加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖。
    使用注解必须使用spring-aop依赖

    2.在类中加入spring的注解(多个不同功能的注解)

    3.在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置

    学习的注解:
    1.@Component
    2.@Respotory
    3.@Service
    4.@Controller
    5.@Value
    6.@Autowired
    7.@Resource

    用户处理请求:
    用户form ,参数name ,age-----Servlet(接收请求name,age)---Service类(处理name,age操作)---dao类(访问数据库的)---mysql

    ==============================================================================================
    第三章 aop

    1.动态代理
    实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。

    jdk动态代理要求目标类必须实现接口

    cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。

    子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

    2.动态代理的作用:
    1)在目标类源代码不改变的情况下,增加功能。
    2)减少代码的重复
    3)专注业务逻辑代码
    4)解耦合,让你的业务功能和日志,事务非业务功能分离。

    3.Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
    Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了, 让开发人员用一种统一的方式,使用动态代理。

    1. AOP(Aspect Orient Programming)面向切面编程
      Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。

    切面的特点: 一般都是非业务方法,独立使用的。
    Orient:面向, 对着。
    Programming:编程

    oop: 面向对象编程

    怎么理解面向切面编程 ?
    1)需要在分析项目功能时,找出切面。
    2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
    3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

    术语:
    1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。
    2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
    3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
    4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
    5)Advice:通知,通知表示切面功能执行的时间。

    说一个切面有三个关键的要素:
    1)切面的功能代码,切面干什么
    2)切面的执行位置,使用Pointcut表示切面执行的位置
    3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。

    5.aop的实现
    aop是一个规范,是动态的一个规范化,一个标准
    aop的技术实现框架:
    1)spring:
    spring在内部实现了aop规范,能做aop的工作。
    spring主要在事务处理时使用aop。
    我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。

    2)aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。

    aspectJ框架实现aop有两种方式:
    .使用xml的配置文件 : 配置全局事务
    使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

    6.学习aspectj框架的使用。
    1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
    在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
    1)@Before
    2)@AfterReturning
    3)@Around
    4)@AfterThrowing
    5)@After

    2)表示切面执行的位置,使用的是切入点表达式。

        com.service.impl
        com.bjpowrnode.service.impl
        cn.crm.bjpowernode.service
    
    
      execution(* *..service.*.*(..))
    

    ====================================================================
    第四章: 把mybatis框架和spring集成在一起,向一个框架一样使用。

    用的技术是:ioc 。
    为什么ioc:能把mybatis和spring集成在一起,像一个框架, 是因为ioc能创建对象。
    可以把mybatis框架中的对象交给spring统一创建, 开发人员从spring中获取对象。
    开发人员就不用同时面对两个或多个框架了, 就面对一个spring

    mybatis使用步骤,对象
    1.定义dao接口 ,StudentDao
    2.定义mapper文件 StudentDao.xml
    3.定义mybatis的主配置文件 mybatis.xml
    4.创建dao的代理对象, StudentDao dao = SqlSession.getMapper(StudentDao.class);

    List<Student> students = dao.selectStudents();

    要使用dao对象,需要使用getMapper()方法,
    怎么能使用getMapper()方法,需要哪些条件

    1.获取SqlSession对象, 需要使用SqlSessionFactory的openSession()方法。
    2.创建SqlSessionFactory对象。 通过读取mybatis的主配置文件,能创建SqlSessionFactory对象

    需要SqlSessionFactory对象, 使用Factory能获取SqlSession ,有了SqlSession就能有dao , 目的就是获取dao对象

    Factory创建需要读取主配置文件

    我们会使用独立的连接池类替换mybatis默认自己带的, 把连接池类也交给spring创建。

    主配置文件:
    1.数据库信息

     <environment id="mydev">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <!--数据库的驱动类名-->
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <!--连接数据库的url字符串-->
                    <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                    <!--访问数据库的用户名-->
                    <property name="username" value="root"/>
                    <!--密码-->
                    <property name="password" value="123456"/>
                </dataSource>
    
    1. mapper文件的位置
       <mappers>
            <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
            <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
        </mappers>
    

    ==============================================================
    通过以上的说明,我们需要让spring创建以下对象
    1.独立的连接池类的对象, 使用阿里的druid连接池
    2.SqlSessionFactory对象
    3.创建出dao对象

    需要学习就是上面三个对象的创建语法,使用xml的bean标签。

    连接池:多个连接Connection对象的集合, List<Connection> connlist : connList就是连接池

    通常使用Connection访问数据库

    Connection conn =DriverManger.getConnection(url,username,password);
    Statemenet stmt = conn.createStatement(sql);
    stmt.executeQuery();
    conn.close();
    

    使用连接池
    在程序启动的时候,先创建一些Connection
    Connection c1 = ...
    Connection c2 = ...
    Connection c3 = ...
    List<Connection> connlist = new ArrayLits();
    connList.add(c1);
    connList.add(c2);
    connList.add(c3);

    Connection conn = connList.get(0);
    Statemenet stmt = conn.createStatement(sql);
    stmt.executeQuery();
    把使用过的connection放回到连接池
    connList.add(conn);

    Connection conn1 = connList.get(1);
    Statemenet stmt = conn1.createStatement(sql);
    stmt.executeQuery();
    把使用过的connection放回到连接池
    connList.add(conn1);

    ==================================================================
    spring的事务处理
    回答问题
    1.什么是事务
    讲mysql的时候,提出了事务。 事务是指一组sql语句的集合, 集合中有多条sql语句
    可能是insert , update ,select ,delete, 我们希望这些多个sql语句都能成功,或者都失败, 这些sql语句的执行是一致的,作为一个整体执行。

    2.在什么时候想到使用事务
    当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。

    在java代码中写程序,控制事务,此时事务应该放在那里呢?
    service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句

    3.通常使用JDBC访问数据库, 还是mybatis访问数据库怎么处理事务
    jdbc访问数据库,处理事务 Connection conn ; conn.commit(); conn.rollback();
    mybatis访问数据库,处理事务, SqlSession.commit(); SqlSession.rollback();
    hibernate访问数据库,处理事务, Session.commit(); Session.rollback();

    4.3问题中事务的处理方式,有什么不足
    1)不同的数据库访问技术,处理事务的对象,方法不同,
    需要了解不同数据库访问技术使用事务的原理
    2)掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务
    3)处理事务的多种方法。

    总结: 就是多种数据库的访问技术,有不同的事务处理的机制,对象,方法。

    5.怎么解决不足
    spring提供一种处理事务的统一模型, 能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。

    使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
    使用spring的事务处理机制,可以完成hibernate访问数据库的事务处理。

    6.处理事务,需要怎么做,做什么
    spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了

    1)spring内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
    事务管理器是一个接口和他的众多实现类。
    接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
    实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
    mybatis访问数据库---spring创建好的是DataSourceTransactionManager
    hibernate访问数据库----spring创建的是HibernateTransactionManager

    怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
    声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用<bean>声明就可以了
    例如,你要使用mybatis访问数据库,你应该在xml配置文件中
    <bean id=“xxx" class="...DataSourceTransactionManager">

    2)你的业务方法需要什么样的事务,说明需要事务的类型。

    说明方法需要的事务:
    事务的隔离级别:有4个值。
    DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
    ➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
    ➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
    ➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
    ➢ SERIALIZABLE:串行化。不存在并发问题。

    事务的超时时间: 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
    单位是秒, 整数值, 默认是 -1.

    事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。
    7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。

            PROPAGATION_REQUIRED
            PROPAGATION_REQUIRES_NEW
            PROPAGATION_SUPPORTS
            以上三个需要掌握的
    
            PROPAGATION_MANDATORY
            PROPAGATION_NESTED
            PROPAGATION_NEVER
            PROPAGATION_NOT_SUPPORTED
    

    3)事务提交事务,回滚事务的时机

    当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit

    当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
    运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如NullPointException , NumberFormatException

    当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
    受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException

    总结spring的事务
    1.管理事务的是 事务管理和他的实现类
    2.spring的事务是一个统一模型
    1)指定要使用的事务管理器实现类,使用<bean>
    2)指定哪些类,哪些方法需要加入事务的功能
    3)指定方法需要的隔离级别,传播行为,超时

    你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。

    spring的事务处理.png

    spring框架中提供的事务处理方案

    1.适合中小项目使用的, 注解方案。
    spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
    @Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
    可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

    使用@Transactional的步骤:
    1.)需要声明事务管理器对象
    <bean id="xx" class="DataSourceTransactionManager">

    2.)开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。
    spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
    spring给业务方法加入事务:
    在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知

             @Around("你要增加的事务功能的业务方法名称")
             Object myAround(){
               开启事务,spring给你开启
                  try{
                     buy(1001,10);
                      spring的事务管理器.commit();
                  }catch(Exception e){
                 spring的事务管理器.rollback();
                  }
                 
             }
    

    3).在你的方法的上面加入@Trancational

    2.适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中
    声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

    实现步骤: 都是在xml配置文件中实现。

    1)要使用的是aspectj框架,需要加入依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
    

    2)声明事务管理器对象

    <bean id="xx" class="DataSourceTransactionManager">
    
    1. 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)

    2. 配置aop:指定哪些哪类要创建代理。

    ================================================================================
    第六章: web项目中怎么使用容器对象。

    1.做的是javase项目有main方法的,执行代码是执行main方法的,在main里面创建的容器对象

      ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    

    2.web项目是在tomcat服务器上运行的。 tomcat一起动,项目一直运行的。

    需求:
    web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。

    怎么实现:
    使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext

    监听器作用:
    1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

    2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

    监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener

     private WebApplicationContext context;
     public interface WebApplicationContext extends ApplicationContext
    

    ApplicationContext:javase项目中使用的容器对象
    WebApplicationContext:web项目中的使用的容器对象

    把创建的容器对象,放入到全局作用域
    key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
    value:this.context

    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

    概念.png ioc.png aop.png aspectj框架的使用.png spring集成mybatis.png spring框架处理事务.png 总图.png

    相关文章

      网友评论

        本文标题:Spring框架学习1:Spring 集成 MyBatis、Sp

        本文链接:https://www.haomeiwen.com/subject/jfizaktx.html