一 事务
1.什么是事务
单个逻辑单元执行一系列的事,要么全成功,要么全不执行。
spring事务的本质是对数据库事务的支持,没有数据库的事务支持,spring是无法完成事务的。
2.为什么需要事务
事务是一系列的动作,其中一个动作出错,必须全部回滚,系统将事务中对数据库的 所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来 一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务 管理是必不可少的
3.spring事务特性
spring所有的事务管理策略类都继承自
org.springframework.transaction.PlatformTransactionManager接口 其中TransactionDefinition接口定义以下特性:事务隔离级别、事务传播行为、事务超时、事务 只读属性、spring事务回滚规则等;
4.声明事务管理配置的两种方法
4.1配置文件的方式
4.1.1 pom文件配置
添加jar
测试需要使用的jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
aop需要使用的jar
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
事务需要使用的jar
<!--事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.1</version>
</dependency>
4.1.2 spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmln s:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans htt p://www.springframework.org/schema/beans/spring-beans.xsd http://www.sprin gframework.org/schema/context https://www.springframework.org/schema/conte xt/spring-context.xsd http://www.springframework.org/schema/tx http://www. springframework.org/schema/tx/spring-tx.xsd http://www.springframework.or g/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置spring扫描包-->
<context:component-scan base-package="com"/>
<!--通过spring配置数据库的连接属性文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--通过spring来配置数据库连接池的数据源对象-->
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<!--配置连接池数据源需要使用四大金刚(数据库连接属性)-->
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--通过spring来配置mybatis的会话工厂和其他相关配置
原来的时候,mybatis的会话工厂由程序员来创建,现在通过spring来创建管理
这个就体现了Spring的IoC特征(控制反转)
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFacto ryBean">
<!--配置SqlSession依赖的数据源对象-->
<property name="dataSource" ref="ds"/>
<!--配置mybatis要使用的类型别名定义-->
<property name="typeAliasesPackage" value="com.aaa.hr.entity"/>
<!--配置mybatis的主配置文件的路径,spring会自动加载mybatis的配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xm l"/>
<!--配置mybatis的Mapper文件的路径:spring中Mapper接口和Mapper文件路径可
以由区别-->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!--通过spring来配置Mybatis的Mapper接口
通过包扫描的方式进行配置
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--配置Mybatis的Mapper接口-->
<property name="basePackage" value="com.aaa.demo.mapper"/>
<!--配置可以创建Mapper接口对象的SqlSession使用的SqlSessionFactory对象
的名字-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactor y"/>
</bean>
<!--配置声明式事务-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdb c.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
<!--配置事务增强-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionMan ager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRES_NEW" rollback- for="java.lang.ArithmeticException"/>
</tx:attributes>
</tx:advice>
<!--aop配置-->
<aop:config proxy-target-class="true">
<aop:pointcut id="p1" expression="execution(* com.aaa.demo.servic e.impl.*.*(..))"/>
<!--通过advisor将切面和切入点关联起来-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="p1"/>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autopro xy>
</beans>
4.2注解的方式
基于@Transactional注解的
<!-- 定义事务 --> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.da tasource.DataSourceTransactionManager">
<!--数据源的引用要跟mybatis的保持一致-->
<property name="dataSource" ref="dataSource"></property>
</bean> <tx:annotation-driven transaction-manager="dataSourceTransactionManager" / >
4.3 事务的隔离级别
1)@Transactional(isolation = Isolation.SERIALIZABLE):最严格的级别,事务串行执行,资源 消耗最大;
2)@Transactional(isolation = Isolation.REPEATABLE_READ):保证了一个事务不会修改已经 由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是 带来了更多的性能损失。
3)@Transactional(isolation = Isolation.READ_COMMITTED):大多数主流数据库的默认事务 等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,该 级别适用于大多数系统。
4)@Transactional(isolation = Isolation.READ_UNCOMMITTED):保证了读取过程中不会读 取到非法数据。
1:Dirty reads–读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读 走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2:non-repeatable reads–不可重复读。比如事务A中两处读取数据-total-的值。在第一读 的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现, total竟然就变成200了,造成事务A数据混乱。
3:phantom reads–幻象读数据。这个和non-repeatable reads相似,也是同一个事务中多 次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了 (比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改 变,而是他的条件数据集改变。比如Select account.id where account.name=“grace”,第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改 成"grace",结果取出来了7个数据。 不可重复读的重点是修改:同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。 幻读的重点在于新增或者删除:同样的条件, 第1次和第2次读出来的记录数不一样。
4.4 常用数据库默认事务隔离级别
常用数据库默认事务隔离级别:
MYSQL:默认为REPEATABLE_READ
SQLSERVER:默认为READ_COMMITTED
ORACLE:默认为READ_COMMITTED
4.5@Transactional注解中常用参数说明
readOnly
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值 为false。例如@Transactional(readOnly=true) rollbackFor
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行 事务回滚。例如:
指定单一异常类:
@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:
@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName
该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常 时,则进行事务回滚。例如:
指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”)
指定多个异常类名称:@Transactional(rollbackForClassName= {“RuntimeException”,”Exception”})
noRollbackFor
该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进 行事务回滚。例如:
指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)
指定多个异常类:
@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) noRollbackForClassName
该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常 时,不进行事务回滚。
例如: 指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”) 指定多个异常类名称: @Transactional(noRollbackForClassName={“RuntimeException”,”Exception”}) propagation 该属性用于设置事务的传播行为
例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) isolation
该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常 使用数据库的默认隔离级别即可,基本不需要进行设置
timeout
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完 成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。 默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是 none,没有超时限制。
二 定时任务
spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关
的包外不需要额外的包,而且支持注解和配置文件两种