Spring第四天讲义

今日内容

  1. Spring的事务管理
  2. Spring和MyBatis框架的集成

1. Spring的事务管理

1.1. 事务是什么?

在操作数据库时(增删改),如果同时操作多次数据,我们从业务希望,要不全部成功,要不全部失败。这种情况称为事务处理。

A转账给B。

第一步,扣除A君账号要转的金额

第二步,增加B君账号的金额

事务:指单个逻辑操作单元的集合

1.2. Spring事务控制我们要明确的

1.JavaEE体系进行分层开发,事务处理位于业务层所以,一般情况下我们使用事务代理,一般放在分层设计业务层

2.spring框架为我们提供了一组事务控制的应用程序接口(API)。

3.spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。

1.3. 案例引出问题

需求:从ID为10086账户给ID为10010账户转账1000元钱。

数据准备:account表(账户):

-------------------------

ID        BALANCE

-------------------------

10010       0

10086    1000

设计一个 Account表

CREATE TABLE `t_account` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`balance` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=10087 DEFAULT CHARSET=utf8;

编写转账案例

1.4. 转账案例分析

结论: 根据上述案例分析, 事务管理应该是在Service层处理

1.5. 数据库并发问题

什么是数据库并发问题?

并发: 多个客户端同时同时访问数据库中某一条数据(秒杀)

数据库可以拥有多个访问客户端,若多个客户端并发地访问数据库中相同的资源,如果没有采取必要的隔离措施,则会导致各种并发问题,破坏数据的完整性。

这些问题归结为5类

包括3类数据读问题(脏读,不可重复读,幻读)

和2类数据更新问题(第一类丢失更新,第二类丢失更新)。 看图

1.5.1. 第一类更新丢失

两个事务更新相同数据,如果一个事务提交,另一个事务回滚,第一个事务的更新会被回滚

1.5.2. 第二类丢失更新

多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变

1.5.3. 脏读

第二个事务查询到第一个事务未提交的更新数据,第二个事务根据该数据执行,但第一个事务回滚,第二个事务操作脏数据

1.5.4. 幻读

一个事务查询到了另一个事务已经提交的新数据,导致多次查询数据不一致

1.5.5. 不可重复读

一个事务查询到另一个事务已经修改的数据,导致多次查询数据不一致

1.6. 数据库事务的隔离级别

问题:上述问题理论上如果出现了应该如何解决?

答:一般情况,数据库都会处理一些事务并发的问题,数据库提供了不同的事务隔离级别来处理不同的事务并发问题,事务隔离级别定义如下:

隔离级别

说明

READ_UNCOMMITED

允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读(相当于没有做任何事务隔离)

READ_COMMITTED

允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生(ORACLE默认级别)

REPEATABLE_READ

对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。(MYSQL默认级别)

SERIALIZABLE

完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。(ORACLE支持)

针对不同隔离级别可以解决的的如下五类问题

1.6.1. 解决丢失更新的方案 

数据库表数据加锁

1,悲观锁

(1) 在操作当前数据的事务开启事务就使用for update 锁住当前数据

(2) Hibernate和MyBatis都有悲观锁对应的解决方案

2,乐观锁

(1) 为表添加一个version字段。当前事务操作的时候都会比对当前事务情况的多次操作的版本号是否一致,如果不一致认为数据已经被更新

(2) Hibernate和MyBatis都有乐观锁对应的解决方案

1.7. Spring对事务的支持

  1. 为什么需要使用Spring是事务

答:使用Spring是事务代理,可以配置一次,不用重复编写事务处理代码!!

Spring框架针对事务处理提供专门的解决方案

Spring的事务管理主要包括3个接口

Spring事务处理接口

描述

TransactionDefinition

封装事务的隔离级别超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性,可通过XML配置具体信息

PlatformTransactionManager

根据TransactionDefinition提供的事务属性配置信息,创建事务。事物管理器

TransactionStatus

封装了事务的具体运行状态。比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等

 

1.7.1. TransactionDefinition

该接口主要定义了:事务的传播行为(规则),事务的隔离级别,获得事务信息的方法。所以在配置事务的传播行为,事务的隔离级别已经需要获得事务信息时,可以通过查阅该类的代码获得相关信息。

TransactionDefinition源码

public interface TransactionDefinition {

//事务的传播行为

int PROPAGATION_REQUIRED = 0;

int PROPAGATION_SUPPORTS = 1;

int PROPAGATION_MANDATORY = 2;

int PROPAGATION_REQUIRES_NEW = 3;

int PROPAGATION_NOT_SUPPORTED = 4;

int PROPAGATION_NEVER = 5;

int PROPAGATION_NESTED = 6;

//事务的隔离级别

int ISOLATION_DEFAULT = -1;

int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

//事务超时管理

int TIMEOUT_DEFAULT = -1;

//获得事务信息

int getPropagationBehavior();

int getIsolationLevel();

int getTimeout();

boolean isReadOnly();

String getName();

}

1.7.1.1. 事务传播规则

Spring在TransactionDefinition接口中定义了七种事务传播规则,规定了事务方法和事务方法发生嵌套调用时事务该如何进行传播

事务传播规则类型

描述

PROPAGATION_REQUIRED

如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务(最常用操作)-Spring默认使用的就是此规则

PROPAGATION_REQUIRES_NEW

创建一个新的事务,如果当前存在事务,则把当前事务挂起

PROPAGATION_SUPPORTS

如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行

PROPAGATION_NOT_SUPPORTED

以非事务方式运行,如果当前存在事务,则把当前事务挂起

PROPAGATION_NEVER

以非事务方式运行,如果当前存在事务,则抛出异常

PROPAGATION_MANDATORY

如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常

PROPAGATION_NESTED

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED

1.7.2. PlatformTransactionManager事务管理器

Spring的事务管理:

1,PlatformTransactionManager:接口统一抽象处理事务操作相关的方法;

1):TransactionStatus getTransaction(TransactionDefinition definition)

根据事务定义信息从事务环境中返回一个已存在的事务,或者创建一个新的事务,并用TransactionStatus描述该事务的状态。

ü 2):void commit(TransactionStatus status)

根据事务的状态提交事务,如果事务状态已经标识为rollback-only,该方法执行回滚事务的操作。

ü 3):void rollback(TransactionStatus status)

将事务回滚,当commit方法抛出异常时,rollback会被隐式调用

2,在使用spring管理事务的时候,首先得告诉spring使用哪一个事务管理器,使用不同的框架(JdbcTemplate,MyBatis,Hibernate/JPA )使用事务管理器都不同

1.7.2.1. PlatformTransactionManager事物管理器的继承体系图

3,常用的事务管理器:

DataSourceTransactionManager:使用JDBC,MyBatis的事务管理器;

1.8. Spring事务的配置

Spring支持编程式事务管理和声明式事务管理。

  1. 编程式事务管理:事务和业务代码耦合度太高。
  1. 明式事务管理:侵入性小,把事务从业务代码中抽离出来,使用AOP配置到配置文件中,提高维护性。

1.8.1. 声明式事务管理-xml方式配置

1.8.1.1. 准备配置文件

在配置文件中引入新的命名空间 tx

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

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/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    http://www.springframework.org/schema/tx

    http://www.springframework.org/schema/tx/spring-tx.xsd

    ">

1.8.1.2. 配置事物管理器-DataSourceTransactionManager

Spring对象事务的支持,必须先配置事务管理器,事务管理器已经封装了事务的具体的处理

DataSourceTransactionManager

使用JDBC,MyBatis的事务管理器;(当前案例使用的Spring的JDBC操作,所以配置这个)

<!-- 1,配置事务管理器(应根据情况使用合适的事务管理器) -->

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<!-- 注入dataSource -->

<property name="dataSource" ref="dataSource"/>

</bean>

<!--

1、切入点(Pointcut):在哪些类,哪些方法上切入(where);

2、增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);

3、切面(Aspect):切面=切入点+通知,通俗点就是:什么时机,什么地点,做什么!

4、织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。

WWW 原则 :

where : 在什么地方切事务

what : 干什么(切事务)

when : 时机(在方法前或者后)

-->

<!-- 事务相关的配置 : 使用AOP面向切面编程(切事务) : 使用 tx: 标签  -->

<!-- tx:advice : 配置事物的标签

id : 唯一标识

transaction-manager : 需要用到的事物管理器

-->

<!-- 2,配置管理事务的“增强” :环绕通知-->

<tx:advice id="txAdvice" transaction-manager="txManager">

<tx:attributes>

<!-- 配置要切的方法 : trans (默认使用的是环绕通知) -->

<tx:method name="trans"/>

</tx:attributes>

</tx:advice>

<!-- 3,面向切面 :  -->

<aop:config >

<!-- 切入点 : where -->

<aop:pointcut expression="execution ( * cn.zj.spring.service..*.*(..))" id="pt"/>

<!-- 配置切面  切面 = 切入点 + 通知

advice-ref 通知的引用

pointcut-ref 切入点的引入

-->

<aop:advisor  advice-ref="txAdvice"  pointcut-ref="pt" />

<!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成) -->

</aop:config>

1.8.1.3. 事物方法的属性细节配置

事务方法属性:

事务方法属性

描述

name

匹配到的方法模式

read-only

如果为true,开启一个只读事务,只读事务的性能较高,但是不能再只读事务中,使用DML

isolation

代表数据库事务隔离级别(就使用默认)

DEFAULT:让spring使用数据库默认的事务隔离级别;

no-rollback-for

如果遇到的异常是匹配的异常类型,就不回滚事务

rollback-for

如果遇到的异常是指定匹配的异常类型,才回滚事务;spring默认情况下,spring只会去回滚RuntimeException及其子类,不会回滚Exception和Thowable

propagation

事务的传播方式(当一个方法已经在一个开启的事务当中了,应该怎么处理自身的事务)

1,REQUIRED(默认的传播属性):如果当前方法运行在一个没有事务环境的情况下,则开启一个新的事务,如果当前方法运行在一个已经开启了的事务里面,把自己加入到开启的那个事务中

2,REQUIRES_NEW:不管当前方法是否运行在一个事务空间之内,都要开启自己的事务

timeout

事务处理的超时时间,默认事物管理自动处理 ,可以手动配置

<tx:advice id="txAdvice" transaction-manager="txManager">

<tx:attributes>

<!-- <tx:method>

name : 需要切面的方法

isolation : 事务的隔离级别 DEFAULT 使用当前数据库默认的隔离级别,不同数据库隔离级别不同(可以不配置)

propagation : 事物的传播规则 ,默认使用 REQUIRED

read-only : 是否是只读事务, DQL配置即可

-->

<!-- 一般DML操作才需要事务,DQL查询操作是不需要事物

* 通配符

-->

<!-- 所有以前缀开都的方法都认为是 查询方法,就不切入事物 -->

<tx:method name="get*" read-only="true"/>

<tx:method name="select*"  read-only="true" />

<tx:method name="find*"  read-only="true"/>

<tx:method name="query*"  read-only="true"/>

<tx:method name="list*"  read-only="true"/>

<!-- 非查询(DQL)方法: DML操作,需要事务管理 -->

<tx:method name="*" />

</tx:attributes>

</tx:advice>

1.8.2. 声明式事务管理-基于注解配置

Spring的声明式事务也支持 注解

1.8.2.1. applicationContext.xml配置文件

<!-- 1,配置事务管理器(应根据情况使用合适的事务管理器) -->

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<!-- 注入dataSource -->

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- 开启注解驱动配置事务

编写此标签:Spring底层就支持注解配置事物,并且已经配置好事物管理器

-->

<tx:annotation-driven transaction-manager="txManager"/>

1.8.2.2. AccountServiceImpl 业务层代码

@Service

/* @Transactional

* 贴上此当前类已经被Spring事务管理

* 注意: @Transactional 只能对当前贴的Service类有效

*  常用属性 :

*   isolation=Isolation.REPEATABLE_READ,  隔离级别

propagation=Propagation.REQUIRED,传播规则

readOnly=true 是否只读事务

*

*/@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)

public class AccountServiceImpl implements AccountService{

@Autowired

private AccountDao dao;

public void trans(Integer transOutId,

Integer transInId, Integer money) {

dao.tranOut(transOutId, money);

System.out.println(1 / 0);// 模拟断电

dao.tranIn(transInId, money);

}

//单独为某一个方法配置具体的事物细节:如查询方法,事物是只读的

@Transactional(readOnly=true)

public Object getUser() {

//查询操作

return null;

}

@Transactional(readOnly=true)

public List<Object> getUsers() {

//查询操作

return null;

}

}

1.8.3. 事物配置的注解和XML配置的选择

Xml配置 : 代码清晰,配置量少,容易维护

注解配置 : 侵入代码,每个Service层类都得配置,针对不同的方法还得配置事务细节:如查询方法配置只读操作,不容易维护

建议选择xml配置

2. 小结

Spring框架出现原因?

早期企业级开发组件(框架) EJB (重量级)不好用

音乐博士,计算机大牛

觉得ejb 不好,写了一本书各种吐槽抨击 ejb

顺便写了一个轻量级 一站式 企业框架 spring

2.1. Spring 核心作用

解耦 (降低程序代码与代码的直接依赖关系)

2.2. 核心功能

Spring容器-下面所有操作都在Spring 容器中完成,Spring就是项目对象的管家

  1. IOC :控制反转(将对象的创建权交给Spring管理)

(1) Xml 配置

① <bean id/name=xxx class = 类的全限定名 scope=作用范围 init-mehtod=初始化方法destory-mehtod=销毁方法>

② 从Spring容器中读取bean对象

(2) 注解配置 -贴在类上即可

① @Component  通用组件扫描创建

② @Controller 表现层(SpringMVC 专用)

③ @Service 业务层专用

④ @Repository 持久层/DAO/Mapper 专用

⑤ @Scope 作用范围

⑥ @PostConstrcut 初始化方法

⑦ @PreDestory 销毁方法

  1. DI : 依赖注入(将对象的属性赋值,对象依赖关系维护交给Spring)

(1) XML配置

① <property name=’’  value/ref=’’> 属性注入

② <constructor-arg  name=参数名 value/ref=’’ >

③ P 命名空间

1) <bean id =xx class =Xxxx p:属性名= p:属性名-ref=引用类型>

(2) 注解配置

① Spring框架制定

1) @Autowired 默认按照类型注入  

  1. 可以贴在 字段(成员编写),set方法,构造函数

2) @Qualifier 从多个相同类型中通过id指定唯一的那个bean

② JavaEE 官方指定

1) @Resource(name=bean的id)

  1. AOP :面向切面编程

(1) AOP 底层原理-Java动态代理

① JDK动态代理 : 只能有接口的类型进行代理

② CGLIB代理 :即可代理有接口类,有可以代理没有接口的

(2) 专业术语

① JoinPoint 连接点(方法)

② PointCut 切入点 (某一类方法,规则)

③ Advice 通知/增强

④ Aspect 切面 = 切入点+通知

⑤ Weaving 织入(Spring自动完成)

  1. Spring事务管理

(1) 配置事务管理器

① JDBC/MyBatis  ---->DataSourceTransactionManager

(2) 事务的隔离级别 4个

(3) 事务的传播规则(行为) 7个

(4) 是否是只读事务

(5) 使用AOP 将事务切入到 业务层

  1. Spring-Jdbc (了解)

(1)  jdbcTemplate 模板类

① Update 更新方法(update,insert,delete)

② queryForObject : 单行查询

③ Query : 多行查询

  1. Spring-test
  2. SpringMVC

Spring (4)框架的更多相关文章

  1. Spring MVC篇一、搭建Spring MVC框架

    本项目旨在搭建一个简单的Spring MVC框架,了解Spring MVC的基础配置等内容. 一.项目结构 本项目使用idea intellij创建,配合maven管理.整体的目录结构如图: 其中ja ...

  2. Spring MVC 框架的架包分析,功能作用,优点

    由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或是软件架构师,在学习和了解一个框架的时候,首先都应该知道的是这个框架的原理和与其有关j ...

  3. SSH(Struts2+Spring+Hibernate)框架搭建流程<注解的方式创建Bean>

    此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblo ...

  4. 从零开始学 Java - 搭建 Spring MVC 框架

    没有什么比一个时代的没落更令人伤感的了 整个社会和人都在追求创新.进步.成长,没有人愿意停步不前,一个个老事物慢慢从我们生活中消失掉真的令人那么伤感么?或者说被取代?我想有些是的,但有些东西其实并不是 ...

  5. Spring+MyBatis框架中sql语句的书写,数据集的传递以及多表关联查询

    在很多Java EE项目中,Spring+MyBatis框架经常被用到,项目搭建在这里不再赘述,现在要将的是如何在项目中书写,增删改查的语句,如何操作数据库,以及后台如何获取数据,如何进行关联查询,以 ...

  6. Spring4.1新特性——Spring缓存框架增强(转)

    目录 Spring4.1新特性——综述 Spring4.1新特性——Spring核心部分及其他 Spring4.1新特性——Spring缓存框架增强 Spring4.1新特性——异步调用和事件机制的异 ...

  7. 手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版)

    手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版) SSM(Spring+SpringMVC+Mybatis),目前较为主流的企业级架构方案.标准的MVC设计模式, ...

  8. Spring Boot 框架@Temporal(TemporalType.DATE)

    使用spring boot框架开发项目时,遇到这样一个问题: 查询pgSQL数据库中表A中某date数据类型的列B,想得到YYYY-MM-DD格式的日期,结果返回的为时间戳(长整型数据). 解决办法: ...

  9. Spring基本框架

    1.Spring基本框架的概念 Spring 框架是一个分层架构,由 7 个定义良好的模块组成.Spring模块构建在核心容器之上,核心容器定义创建.配置和管理bean的方式.组成Spring框架的每 ...

  10. 【WEB】初探Spring MVC框架

    Spring MVC框架算是当下比较流行的Java开源框架.但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了.“心塞”的同时,只好默默 ...

随机推荐

  1. 深入理解WebRTC

    Web Real-Time Communication(Web实时通信,WebRTC)由一组标准.协议和JavaScript API组成,用于实现浏览器之间(端到端)的音频.视频及数据共享. WebR ...

  2. legend3---16、网站的安全性问题

    legend3---16.网站的安全性问题 一.总结 一句话总结: 通过客户端传递参数的方式也是有些危险,需要注意 单纯的获取数据的方法还好,但是 修改数据库方法一定要同时做前后端验证 1.php的b ...

  3. socket_timeout

    https://github.com/pika/pika/blob/03542ef616a2a849e8bfb0845427f50e741ea0c6/docs/examples/using_urlpa ...

  4. [转] node.js express的安装与部署,以及pm2下的运行启动。

    node.js 下的express 安装可以参考官方网站的 http://www.expressjs.com.cn/ 这里主要讲一下一些不同的地方,将我们生成的dist文件夹里的文件放在public里 ...

  5. iOS12 中的后台下载与上传

    严格意义上来说,iOS并不能像Android一样,真的在后台开启一个下载Service,一直下载.但是它可以进行在系统允许范围内的后台上传和下载. 当使用 NSURLSessionConfigurat ...

  6. i18n 语言码和对应的语言库

    语言码 语言名称 af Afrikaans am Amharic ar Arabic az Azerbaijani be Belarusian bg Bulgarian bh Bihari bn Be ...

  7. ES6 Syntax and Feature Overview

    View on GitHub Note: A commonly accepted practice is to use const except in cases of loops and reass ...

  8. 阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_16-课程预览功能开发-接口测试

    cms和课程的微服务重启 从数据库内找一条数据 进入到了断点 拼装课程信息 ,然后进行远程调用 抛出异常 可能是开了两个cms服务的事,负载均衡 到了另外一个服务里面 ,关掉一个 把02关掉,重启cm ...

  9. Apache工作模式切换

    一.apache运行模式切换 apache比较常用的工作模式有worker以及prefork两种方式 1.编译安装: 如果在编译时候不指定,系统默认的是prefork模式.如果需要换成worker模式 ...

  10. iOS 将一个UIImage缩放到指定Size

    这方法挺实用的,直接调用就可以得到想要的size. //将一个UIImage缩放变换到指定Size -(UIImage*) OriginImage:(UIImage *)image scaleToSi ...