mysql隔离级别:未提交读、已提交读、可重复读、序列化
oracle隔离级别:已提交读、序列化
1.事务基础
通常的观念认为,事务仅与数据库相关。
事务必须服从ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性 (isolation)和持久性(durability)的缩写。
原子性:表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。
一致性:表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
隔离性:表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
持久性:表示已提交的数据在事务执行失败时,数据的状态都应该正确。
事务通俗的理解:要么全部执行成功,要么全部执行失败。
既然事务的概念从数据库而来,那Java事务是什么?之间有什么联系?
实际上,一个Java应用系统,如果要操作数据库,则通过JDBC来实现的。增加、修改、删除都是通过相应方法间接来实现的,事务的控制也相应转移到Java程序代码中。
因此,数据库操作的事务习惯上就称为Java事务。
2.事务类型
事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。
2.1 JDBC事务
JDBC 事务是用 Connection 对象控制的。同一事务中所有的操作,都在使用同一个Connection对象。JDBC事务默认是开启的,并且是默认提交。
1 private Connection conn = null;
2
3 private PreparedStatement ps = null;
4
5 try {
6 conn.setAutoCommit(false); //将自动提交设置为false
7
8 ps.executeUpdate("修改SQL"); //执行修改操作
9
10 ps.executeQuery("查询SQL"); //执行查询操作
11
12 conn.commit(); //当两个操作成功后手动提交
13
14 } catch (Exception e) {
15
16 conn.rollback(); //一旦其中一个操作出错都将回滚,使两个操作都不成功
17
18 e.printStackTrace();
19
20 }
JDBC Connection 接口提供了两种事务模式:自动提交和手工提交
JDBC中的事务java.sql.Connection 的三个方法与事务有关:
setAutoCommit(boolean); 设置是否为自动提交事务,如果true(默认值为true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置为false,需要手动提交事务。
commit(); 提交结束事务。
rollback(); 回滚结束事务。
保存点(SavePoint)
JDBC定义了SavePoint接口,提供在一个更细粒度的事务控制机制。当设置了一个保存点后,可以rollback到该保存点处的状态,而不是rollback整个事务。
Connection接口的setSavepoint和releaseSavepoint方法可以设置和释放保存点。
JDBC规范虽然定义了事务的以上支持行为,但是各个JDBC驱动,数据库厂商对事务的支持程度可能各不相同。如果在程序中任意设置,可能得不到想要的效果。为此,JDBC提供了DatabaseMetaData接口,提供了一系列JDBC特性支持情况的获取方法。
比如,通过DatabaseMetaData.supportsTransactionIsolationLevel方法可以判断对事务隔离级别的支持情况,通过DatabaseMetaData.supportsSavepoints方法可以判断对保存点的支持情况。
2.2 JTA事务
JTA(Java Transaction API)提供了跨数据库连接(或其他JTA资源)的事务管理能力,JTA事务管理则由JTA容器实现。
2.3 Spring容器事务
Spring事务管理涉及的接口及其联系:
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
基本的事务属性的定义:
事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
事务属性包含了5个方面:
传播行为、隔离规则、回滚规则、事务超时、是否只读
TransactionDefinition:
public interface TransactionDefinition {
int getPropagationBehavior(); // 返回事务的传播行为
int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getTimeout(); // 返回事务必须在多少秒内完成
boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
}
事务的属性可同通过注解方式
@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
默认情况下,一个有事务方法, 遇到RuntimeException 时会回滚 . 遇到 受检查的异常 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常})
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
//事务的传播行为
Propagation propagation() default Propagation.REQUIRED;
//事务的隔离级别,此处使用后端数据库的默认隔离级别
Isolation isolation() default Isolation.DEFAULT;
//事务的超时时间,-1为无限制
int timeout() default -1;
//读写事务
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
//遇到指定的异常不回滚
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
3.事务隔离级别
1.隔离级别
1). 未提交读(read uncommitted,级别1)
允许一个事务读取另外一个事务没有提交的数据
脏读即为事务1读到了事务2未提交的数据。若事务2回滚,则事务1读到了脏数据。
说明:当事务B对data进行了修改但是未提交事务,此时事务A对data进行读取,并使用事务B修改的数据做业务处理。
2). 已提交读(read committed,级别2)
一个事务只能读取另外一个事务已经提交的数据(Oracle默认隔离级别)
不可重复读即为事务2在事务1第二次读取时,提交了数据,导致事务1前后两次读取的数据不一致。
事务A、事务B同时对data进行访问,事务A对data进行读取,事务B对data进行修改,当事务A第一次对data进行读取完后事务B提交,此时当事务A第二次读取该数据时的数据就与第一次读取的数据不同,这种情况称为不可重复读;
3). 可重复度(repeatable read,级别4)
在同一个事务内的查询与事务开始时查询结果一致(mysql默认隔离级别),即:事务2在事务1第二次读取时,提交了数据,事务1前后两次读取的数据依然一致。
幻读即为事务2在事务1第二次读取符合条件的数据时,修改提交了数据,若修改的数据符合事务1取数条件,则事务1读到的数据集不一致(产生幻觉,数据莫名其妙的多了或少了)。
data 表有一条数据,事务A对data进行读取, 事务B对data进行数据新增 ,此时事务A读取只有一条数据,而最后实际data是有两条数据,就好象发生了幻觉一样情况成为幻读;
4). 序列化(serializable,级别8)
数据库最高的隔离级别,要求所有的 SQL 都会按照顺序执行
事务2在事务1未提交时,事务2不会开始执行(包括查询)
2.查看当前会话隔离级别
SELECT @@tx_isolation;
3.设置当前会话隔离级别
set session transaction isolation level repeatable read;
4.查看系统当前隔离级别
select @@global.tx_isolation;
5.查看系统当前隔离级别
set global transaction isolation level repeatable read;