活动
状态。没有刷新到磁盘
时,我们就说该事务处在部分提交的
状态。活动的
或者没有刷新到磁盘部分提交的
状态时,可能遇到了某些错误(数据库自身的错误、操作系统错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在失败
的状态。失败的
状态,那么就需要把已经修改的事务中的操作还原到事务执行前的状态。换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称之为回滚
。当回滚
操作完成后,也就是数据库恢复到执行事务之前的状态,我们就说该事务处在了中止的
状态部分提交的
状态的事务将修改过的数据都同步到磁盘
上之后,我们就可以说该事务处在了提交的
状态。start transaction # 或者 begin
start transaction
对比 begin
可以在后面添加一些修饰符
read only
表示是一个只读事务read write
表示当前事务是一个读写事务with consistent snapshot
启动一致性读写commit # 提交事务
rollback # 回滚事务
rollback to [saveport] # 回滚到保存点
# 注意:此时事务还没有结束 要表示一个事务结束要么是 commit 要么是 rollback 我们的事务状态只有提交的、中止的,没有回滚到保存点的
Mysql中有变量 autocommit
也就是说这个变量是开启状态,那么隐式事务就是一个开启的状态,有哪些情况是隐式事务在发挥作用的结果呢
start transaction
或者 begin
语句开启另一个事务那么会隐式提交上一个事务autocommit
系统变量的值为OFF
我们手动调为 ON
时也会隐式提交前句所属的事务LOCK TABLES
、UNLOCK TABLES
等关于锁的语句也会 隐式提交
前句所属的事务修改了
另一个未提交
的sessionB修改过的数据,那就意味着发生了脏写
读取到了
另一个 未提交
的sessionB修改过的数据,那就意味着发生了脏读
,因为此时读取到的数据是不可靠的是 sessionB 事务下的临时数据,并没有持久化到数据库中读取
了一个字段,然后sessionB更改
了改字段。之后sessionA又读取了改字段发现值不同了,那就意味着发生了不可重复读
读取
数据,然后sessionB在该表中插入了一些新的行,之后如果sessionA再次读取
同一张表发现多了几行,那就意味着发生了幻读
3.1介绍了并发事务在执行过程中可能遇到的问题,这些问题有些比较严重,我们按照轻重缓急排序一下
脏写 > 脏读 > 不可重复读 > 幻读
舍弃了一部分隔离性来换取一部分性能,这里就体现在隔离级别上:隔离级别越低,并发问题发生的也就比较多
MySQL 默认的隔离级别是REPEATABLE READ
我们可以手动修改事务的隔离级别
# 查看隔离级别 MySQL 5.7.20以前
show variables like 'tx_isolation'
# MySQL 5.7.20 之后引入了 transaction_isolation 来替换 tx_isolation
show variables like 'transaction_isolation'
# 任何版本都可以使用以下语句
select @@transaction_isolation;
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE
设置时使用GLOBAL或者SESSION的影响
GLOBAL
关键字(在全局范围影响)SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET GLOBAL TRANSACTION_ISOLATION = 'SERIALIZABLE';
当前已经存在的会话无效
只对执行完该语句之后产生的会话起作用
SESSION
关键字(在会话范围内影响)SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET SESSION TRANSACTION_ISOLATION = 'SERIALIZABLE';
对当前会话的所有后续的事务有效
如果在事务之间执行,则对后续的事务有效
该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务
PlatFormTransactionMangeer
:事务管理器 (用来管理事务,包含事务的提交、回滚)TransactionDefinition
:事务定义信息(隔离,传播,超时,只读)TransactionStatus
:事务具体运行状态public interface PlatformTransactionManager extends TransactionManager {
// 获取事务状态信息
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
//回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
从上图可以看到PlatformTransactionManager主要有四种实现类
public interface TransactionDefinition {
// 返回事务的传播行为
int getPropagationBehavior();
// 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getIsolationLevel();
// 返回事务必须在多少秒内完成
int getTimeout();
// 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
boolean isReadOnly();
}
public interface TransactionStatus{
// 是否是新的事务
boolean isNewTransaction();
// 是否有保存点
boolean hasSavepoint();
// 设置为只回滚
void setRollbackOnly();
// 是否为只回滚
boolean isRollbackOnly();
// 是否已完成
boolean isCompleted;
}
声明式事务主要就是 @Transactional
注解
@EnableTransactionManagement
开启事务管理功能<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
@Transactional
注解加入到合适的方法上去@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
/**
* 在配置文件中有多个 TransactionManager,可以使用该属性指定选择哪个事务管理器
*/
@AliasFor("transactionManager")
String value() default "";
/**
* 在配置文件中有多个 TransactionManager,可以使用该属性指定选择哪个事务管理器
*/
@AliasFor("value")
String transactionManager() default "";
/**
* 事务的传播行为,默认值REQUEIRED
*/
Propagation propagation() default Propagation.REQUIRED;
/**
* 事务的隔离度,默认值采用DEFAULT
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* 事务的超时时间默认值 -1 ,如果超过该时间限制但事务还没有完成,则自动回滚事务
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* 指定事务是否为只读事务,默认值false,为了忽略哪些不需要事务的方法,比如读取数据,可以设置为true
*/
boolean readOnly() default false;
/**
* 用于指定能够触发事务鬼滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过 , 分隔
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* 同上,使用全类名字符串
*/
String[] rollbackForClassName() default {};
/**
* 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过 , 分隔
*/
Class<? extends Throwable>[] noRollbackFor() default {};
/**
* 同上,使用全类名字符串
*/
String[] noRollbackForClassName() default {};
}