Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web

Java
334
0
0
2023-05-25

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>my sql -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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

定义 StudentDao 接口

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

定义映射文件 mapper

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

定义 Service 接口和实现类

接口定义:

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

实现类定义:

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web

定义 MyBatis 主配置文件

在 src 下定义 MyBatis 的主配置文件,命名为 mybatis.xml。

这里有两点需要注意:

(1)主配置文件中不再需要数据源的配置了。因为数据源要交给 Spring 容器来管理了。

(2)这里对 mapper 映射文件的注册,使用<package/>标签,即只需给出 mapper 映射文件所在的包即可。因为 mapper 的名称与 Dao 接口名相同,可以使用这种简单注册方式。这种方式的好处是,若有多个映射文件,这里的配置也是不用改变的。当然,也可使用原来的<resource/>标签方式。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

修改 Spring 配置文件

(1) 数据源的配置(掌握)

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

Druid 数据源 DruidDataSource

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

配置 连接池 :

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Spring 配置文件:

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

(2) 从属性文件读取数据库连接信息

为了便于维护,可以将数据库连接信息写入到属性文件中,使 Spring 配置文件从中读取数据。

属性文件名称自定义,但一般都是放在 src 下。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

<context:property-placeholder/>方式(掌握)

该方式要求在 Spring 配置文件头部加入 spring-context.xsd 约束文件

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

(3) 注册 SqlSessionFactoryBean

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

(4) 定义 Mapper 扫描配置器 MapperScannerConfigurer

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

向 Service 注入接口名

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Spring 配置文件全部配置

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Spring 事务

Spring 的事务管理

事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层,即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。

在 Spring 中通常可以通过以下两种方式来实现对事务的管理:

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

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

Spring 事务管理 API

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

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

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

A、常用的两个实现类

PlatformTransactionManager 接口有两个常用的实现类:

DataSource TransactionManager:使用 JDBC 或 MyBatis 进行数据库操作时使用。

Hibernate TransactionManager:使用 Hibernate 进行持久化数据时使用。

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

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

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

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

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

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

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

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

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

(2) 事务定义接口

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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()方法会创建一个事务,并在其中执行。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

b、PROPAGATION_SUPPORTS

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

c、 PROPAGATION_REQUIRES_NEW

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限, sql 语句 的执行时长。

注意,事务的超时时限起作用的条件比较多,且超时的时间计算点较复杂。所以,该值一般就使用默认值即可。

程序举例环境搭建

举例:购买商品 trans_sale 项目

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

实现步骤:

Step0:创建数据库表

创建两个数据库表 sale , goods

sale 销售表

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

goods 商品表

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step3:定义 dao 接口

定义两个 dao 的接口 SaleDao , GoodsDao

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

SaleDao.xml

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

GoodsDao.xml

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step5:定义异常类

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step6:定义 Service 接口

定义 Service 接口 BuyGoodsService

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step7:定义 service 的实现类

定义 service 层接口的实现类 BuyGoodsServiceImpl

  1. 类定义

  2. Dao 属性

  3. Buy 方法

Step8:修改 Spring 配置文件内容

声明 Mybatis 对象

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

声明业务层对象

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step9:定义测试类

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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. 声明事务管理器

  2. 开启注解驱动

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

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

使用 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:在容器中添加事务管理器

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step4:配置事务通知

为事务通知设置相关属性。用于指定要将事务以什么方式织入给哪些方法。

例如,应用到 buy 方法上的事务要求是必须的,且当 buy 方法发生异常后要回滚业务。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step5:配置增强器

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step6:修改测试类

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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 页面

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step4:定义 RegisterServlet(重点代码)

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step5:定义 success 页面

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step6:web.xml 注册 Servlet

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step7:运行结果分析

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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 中注册该监听器。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

Step4:获取 Spring 容器对象

在 Servlet 中获取容器对象的常用方式有两种:

(1) 直接从 ServletContext 中获取

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

(2) 通过 WebApplicationContextUtils 获取

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

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web image.png

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

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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也称为容器
  3. 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)面向切面编程
  2. 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框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 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);

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web 概念.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web ioc.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web aop.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web aspectj框架的使用.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web spring集成mybatis.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web spring框架处理事务.png

Spring框架学习1:Spring 集成 MyBatis、Spring 事务、Spring 与 Web