文章目录

  • 第一章 Spring的AOP案例
  • 1.1 案例简介
  • 1.2 基于XML的配置实现
  • 1.3 基于注解的配置实现
  • 第二章 Spring中的事务
  • 2.1 事务的回顾
  • 2.1.1 事务的概念
  • 2.1.2 事务的四大特性
  • 2.1.3 关于事务并发问题
  • 2.1.4 关于事务隔离级别(解决是事务并发问题的)
  • 2.1.5 关于事务传播行为
  • 2.2 Spring中事务的API
  • 2.2.1 PlatformTransactionManager接口
  • 2.2.2 事务配置相关标签及属性
  • 2.3 Spring基于XML的事务配置
  • 2.3.1 配置步骤
  • 2.3.2 标签详解
  • 2.4 Spring基于半注解的事务配置
  • 2.4.1 配置步骤
  • 2.4.2 注解详解
  • 2.5 Spring全注解的事务开发
  • 2.5.1 配置步骤
  • 2.5.2 注解详解
  • 第三章 Spring中的模板
  • 3.1 Spring中的模板对象


第一章 Spring的AOP案例

1.1 案例简介

案例需求

实现基于Spring的事务控制。要求使用Spring的IoC和Aop。

表结构介绍

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

1.2 基于XML的配置实现

1 加入jar包依赖
2 创建java基础代码:
	pojo: Account
	service:AccountService、AccountServiceImpl
	dao: AccountDao
	
	service:
		依赖注入dao对象
		tips:依赖注入,注入的是接口的实现类对象,底层实现是Spring框架通过动态代理为我们生成的实现类对象
		
3 创建resource配置文件
	tips:在resource目录下创建文件夹要用/而不是.  如com/he/dao 采用.创建出的文件夹不是多级的
	Mybatis的Mapper文件中部分飘红不用管它
	编写dao层的映射文件	
	
	
4 创建事务管理工具包
	事务切面增强类
		初始化:当前线程与连接对象绑定
		开启事务:获取连接
		提交事务
		回滚事务
		释放连接

5 创建Spring配置文件
	配置dao
		配置数据源:加载properties配置文件
		配置SQLsessionFactoryBean
		扫描dao层接口,配置扫描器
	
	配置service
	
	配置aop
		配置切入点
		配置织入
			前置
			后置
			异常
			最终
		
6 测试代码
	service类上alt+enter直接生成测试类

1.3 基于注解的配置实现

1 配置IOC
	创建Spring配置类SpringConfig
		@Configuration:声明是配置类
		@Import:根据功能拆分为两个配置类JDBCConfig、MybatisConfig
		
	创建JDBCconfig:
		@PropertySource:引入资源文件jdbc.properties
		配置DataSource数据源:驱动、url、用户名、密码
		配置连接对象:提供事务切面通知类使用,绑定了事务使用的是同一个连接对象
		
	创建MyBatisConfig:
		配置SQLSessionFactoryBean对象
			配置数据源
			配置pojo别名
		配置dao 扫描器对象
		
		SpringConfig:
			@ComponentScan: 开启SpringIoC的注解扫描
		

2 配置AOP:	
	创建TransactionManager:
		依赖注入连接对象
		@Aspect:声明为切面类
		@Pointcut:配置切入点表达式
		@Around:环绕通知事务方法
		
	SpringConfig:
			@EnableAspectJAutoProxy:开启SpringAOP的注解扫描

3 测试:
	@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境
	@ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件,引入IOC,引入AOP
	执行测试方法

第二章 Spring中的事务

2.1 事务的回顾

2.1.1 事务的概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。从而确保了数据的准确与安全。

例如:A——B转帐,对应于如下两条sql语句:

/*转出账户减钱*/
  update account set money=money-100 where name=‘a’;
  /**转入账户加钱*/
  update account set money=money+100 where name=‘b’;

这两条语句的执行,要么全部成功,要么全部不成功。

2.1.2 事务的四大特性

  • 原子性:一个事务内的操作,要么都成功,要么都失败。很经典的例子:转账,汇款和收款要成功都成功,要失败都失败。
  • 一致性:指的是数据的一致性,和原子性其实是一件事情,只不过描述的角度不一样,原子性是从事务的操作的角度,一致性是从数据的角度来描述的,比如转账之前(1000,1000),如果转账100,那么数据状态应该是(900、1100),不应该出现中间状态(900,1000)或者(1000,1100)
  • 隔离性:事务并发的时候,比如事务1做的动作给员工涨工资2000块,但是此时事务还没有提交,事务2去查询工资发现工资多了2000块,这就是脏读。解决方法就是建立事务之间的隔离机制。
  • 持久性:事务一旦提交,事务提交,变化即生效。即使数据库服务器宕机,那么恢复之后,数据也应该是事务提交之后的状态,不应该回滚到以前了。

2.1.3 关于事务并发问题

  • 脏读( 读到了 未提交的数据 Read_uncommited)
  • 财务人员今天心情不好,状态不好,误操作发起事务1给员工张三本月涨了1w块钱工资,但是还没有提交事务
  • 张三发起事务2,查询当月工资,发现多了1W块钱,涨工资了,财务人员发现不对劲,把操作撤回,把涨工资的事务1给回滚了
  • 幻读(幻读出现在增加insert和删除delete的时候 Read_commited
  • 比如事务1查询工资表中工资为1w的员工的个数(10个员工),此时事务1还没有结束
  • 正在这个时候,事务2,人力部门有两个新员工入职,他们的工资也是1w,人力部门通过事务2向工资表插入了两条记录,并且提交事务了
  • 这个时候,事务1又去查询工资为1w的员工个数,发现多了两个员工(12个人),见鬼了,这种情况就叫做幻读
  • 不可重复读(出现在修改update的时候 repeatable read
  • 员工发起事务1查询工资,工资为1w,事务1尚未关闭
  • 人力部门发起事务2给你涨了工资,涨工资到1.2W(update你的工资表的字段信息),并且提交了事务了。
  • 此时,事务1又再次查询自己的工资,发现工资为1.2W,原有的1w这个数据已经读不到了,这就叫做不可重复读

2.1.4 关于事务隔离级别(解决是事务并发问题的)

  • 极端模式:读未提交 Read_uncommited,就好比十字路口没有红绿灯一样,效率高,但是风险也高,此时什么事务控制都没有。不要使用这种模式
  • 读已提交 Read_commited,顾名思义,其他事务提交之后,才能读取到这个事务提交的数据,这种模式能解决脏读(因为脏读事务是没提交造成的)问题,解决不了幻读和不可重复读(因为这两个问题的产生就是insert delete update的时候提交了事务造成的)
  • 可重复读 Repeatable_Read,可以进行数据重复读, 解决了脏读和不可重复读的问题
  • 极端模式:串行化:所有的事务一个个来,不争不抢,一个事务处理完了,另外一个事务继续进行,这样不会出现并发问题。比如ATM机
  • 默认:DEFAULT,默认是数据库的默认,默认模式来源于上面四种模式之一,mysql数据库默认隔离级别可重复读Repeatable_Read,oracle数据库默认级别读已提交Read_commited
  • 设置事务隔离级别
  • read uncommitted 未提交读,脏读,不可重复读,虚读都可能发生.
  • read committed 已提交读,避免脏读,但是不可重复读和虚读有可能发生(Oracle默认)
  • repeatable read 可重复读,避免脏读,不可重复读,但是虚读有可能发生(MySql默认)
  • serializable 串行化的,避免脏读,不可重复读,虚读的发生
  • 查看当前的事务隔离级别:SELECT @@TX_ISOLATION;

2.1.5 关于事务传播行为

我们的事务往往加载service层方法上,那么我们现在的业务简单些,直接service调用dao层方法,以后可能涉及service层方法A()直接调用service层方法B()。那么此时A()和B()都有自己的事务控制,那么相互调用的时候就会有问题啊,A和B应该有一个关于事务的协商机制,这种机制就叫做事务的传播行为

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)

2.2 Spring中事务的API

2.2.1 PlatformTransactionManager接口

  • 实现类:org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或MyBatis 进行持久化数据时使用
  • 实现类:org.springframework.orm.hibernate5.HibernateTransactionManager 使用Hibernate版本进行持久化数据时使用
  • 配置spring的事务管理对象
<!-- spring的声明式事务 AOP实现,事务管理类DataSourceTransactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

2.2.2 事务配置相关标签及属性

  • 事务配置<tx:advice>通知标签
  • 属性id:自定义唯一表示
  • transaction-manager属性:事务管理类,配置事务管理类的id属性值
  • 事务属性配置<tx:attributes>子标签
  • <tx:method>事务方法标签
  • 属性name:方法名
  • 属性read-only:是否只读事务,查询都是只读,其他是非只读; 默认配置为false
  • 属性propagation:事务的传播行为,默认配置REQUIRED或者SUPPORTS
  • 属性isolation:事务隔离级别,默认配置DEFAULT
  • 属性timeout:事务超时时间,配置-1
  • 属性no-rollback-for:遇到什么异常不回滚,配置异常类名,多个类逗号分开
  • 属性rollback-for:遇到什么异常回滚
  • 以上回滚属性不配置,遇到异常就回滚
  • aop切面配置<aop:config>标签
  • <aop:advisor>子标签
  • 属性advice-ref:引用通知(增强),配置tx:advice标签的属性值
  • 属性pointcut:切点配置

2.3 Spring基于XML的事务配置

Spring获取当前的服务名 spring获取当前事务_spring

2.3.1 配置步骤

基于XML的Spring事务控制:
	1 配置事务管理器对象:Spring框架提供:配置切面类bean
	
	2 配置事务的通知(增强):如何进行事务的增强控制 advice
		进行事务相关属性的配置:attribute
			配置不同方法事务增强的属性:method
				增删改(1类) :默认的
				查询(2类):修改为只读,有事务就用,没事务不增加
							
	3 AOP配置:配置哪些方法需要增强 config
		1 配置切入点表达式:service中所有的方法事务增强 pointcut
		2 配置与事务通知和切入点相关联 	advisor

2.3.2 标签详解

tx:advice

<!--
	作用:
		用于配置事务的通知。
	出现位置:
		beans标签内部都可定义
	属性:
		id:为事务通知提供一个唯一标识。
		transaction-manager:为事务通知指定一个事务管理器的id引用。默认值是transactionManager。
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">

tx:attribute

<!--
	作用:
		用于配置事务的属性。
	出现位置:
		要求写在<tx:advice>标签内部
-->
<tx:attributes>

tx:method

<!--
	作用:
		用于配置每个需要事务支持的方法,所使用的特征。
	出现位置:
		要求写在<tx:attributes>标签内部
	属性:
		name:指定方法名称。支持通配符的配置方式。例如:*表示所有方法 find*表示以find开头的方法。
		read-only:指定是否为只读事务。默认值:false,表示非只读。只有查询方法可以设置为true。
		propagation:指定事务的传播行为。默认值是REQUIRED,表示必须有事务。查询方法设置为SUPPORTS,表示有事务就支持,没有事务就以非实物
		timeout:指定事务的超时时间。默认值是-1,表示永不超时。取值为正整数,以秒为单位。
		isolation:指定事务的隔离级别。默认值是DEFAULT,表示采用数据库的默认隔离级别,不同数据库的默认隔离级别不一样,mysql为REPEATABLE READ,Oracle为READ COMMITTED。其他取值还有:READ UNCOMMITTED和SERIALIZABLE。隔离级别越高执行效率越低,反之亦然。
		rollback-for:用于指定一个异常,当产生该异常时,事务回滚。产生其他异常时,事务不回滚。没有默认值。即,产生任何异常事务都回滚。
		no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚。产生其他异常时,事务回滚。没有默认值。即,产生任何异常事务都回滚。
-->
<tx:method name="*" propagation="REQUIRED" read-only="false" timeout="-1" isolation="" rollback-for="" no-rollback-for=""/>

aop:advisor

<!--
	作用:
		用于建立通知和切入点表达式的关系
	出现位置:
		要求写在<aop:config>标签内部
	属性:
		id:用于指定通知器的唯一标识
		advice-ref:用于指定通知的引用
		pointcut-ref:用于指定切入点表达式的引用
		pointcut:用于指定切入点表达式
		order:当配置多个advisor,用于指定执行优先级
-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1" id="" pointcut="" order=""></aop:advisor>

2.4 Spring基于半注解的事务配置

Spring获取当前的服务名 spring获取当前事务_数据_02

2.4.1 配置步骤

半注解的形式:
	1 开启Spring事务的注解扫描
	2 给类或者方法上@Transactional开启Spring的事务控制
	3 如何对事务进行控制:
		@Transactional注解中属性:
			增删改:可以使用默认
			查:如@Transactional(readOnly = true...),设置属性
			tips:注解作用就近原则,优先使用方法上的注解,类上的注解不生效

2.4.2 注解详解

@Transactional

/**
 * 此注解是Spring注解配置事务的核心注解,无论是注解驱动开发还是注解和XML混合开发。
 * 只有涉及配置事务采用注解的方式,都需要使用此注解。
 * 通过源码我们看到,该注解可以出现在接口上,类上和方法上。分别表明:
 * 		接口上:当前接口的所有实现类中重写接口的方法有事务支持。
 * 		类上:当前类中所有方法有事务支持。
 * 		方法上:当前方法有事务的支持。
 * 		优先级:
 * 			方法上>类上>接口上。
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

}

2.5 Spring全注解的事务开发

spring基于全注解的事务控制配置,我们可以沿用上一个案例中的基础代码,只需要把xml配置部分改为注解实现。在前面的课程学习中,针对注解驱动配置IoC和AOP已经都讲过了,所以我们只需要改造即可。只是需要一个注解替换掉xml配置文件中的<tx:annotation-driven transaction-manager="transactionManager"/>配置。

Spring获取当前的服务名 spring获取当前事务_spring_03

2.5.1 配置步骤

纯注解形式:
	1 注解@EnableTransactionManagement开启Spring事务的注解扫描
	2 给类或者方法上@Transactional开启Spring的事务控制
	3 创建事务管理类TransactionConfig
		配置Spring框架提供的事务管理器对象

2.5.2 注解详解

@EnableTransactionManagement

源码

/**
 * 此注解是Spring支持注解驱动事务配置的标志。
 * 表明Spring开启注解事务配置的支持。
 * 是注解驱动开发事务配置的必备注解。
 * 它是用于替代<tx:annotation-driven transaction-manager="transactionManager"/>标签
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

}

第三章 Spring中的模板

3.1 Spring中的模板对象

在Spring框架中,为我们提供了很多模板对象。这些模板对象,把开发中繁琐重复的部分全部进行了封装,使用之后大大的简化了我们开发。同时,降低了我们的上手难度,让我们可以更加简单直接的实现业务需求。这也是我们在Spring框架课程第一天介绍的Spring框架优势中提到的。

Spring框架提供的模板对象有以下这些:

对象名称

所在包

说明

TransactionTemplate

org.springframework.transaction.support

用于通过编程实现事务控制的模板对象

JdbcTemplate

org.springframework.jdbc.core

用于简化JDBC操作的模板对象

RedisTemplate

org.springframework.data.redis.core

用于简化Redis操作的模板对象

RabbitTemplate

org.springframework.amqp.rabbit.core.RabbitTemplate

用于简化RabbitMQ消息队列操作的模板对象(RabbitMQ后面课程讲解)

JmsTemplate

org.springframework.jms.core

用于简化ActiveMQ消息队列的模板对象

HibernateTemplate

org.springframework.orm.hibernate5

用于简化操作Hibernate框架的模板对象(Hibernate框架现在实际开发中基本已经不用了)

RestTemplate

org.springframework.web.client

用于简化发送Rest风格请求的模板对象(Rest风格请求在SpringMVC课程中讲解)