什么是事务
事务就是指要做或者所作的事情。在计算机术语中是指访问或者更新数据库中的各种数据项的一个执行单元。事务通常由高级数据库或者编程语言书写的程序所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
为什么要事务
事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。
事务的四个特性(ACID)
- 原子性(atomicity):一个事务是一个不可分割的工作单位,要么执行成功,要么执行失败
- 一致性(consistency):事务必须使数据库从一个一致性到另一个一致性。
- 隔离性(isolation):一个事务的执行不能被其他事务影响,一个事务的执行及操作的数据对于并发的事务是隔离的,并发执行的事务互不影响。
- 持久性(durability):如果事务提交成功,则数据的改变永久保存下来。
注:一致性保证数据的致性,例如总数不变即为一致,数据发生改变,相应数据的也应该有所反应,否则数据将会出现混乱,丢失或者增加。而其他三个特性可以说为一致性做了保障
事务的类型
- jdbc事务
- JTA(Java Transaction API事务
- 容器事务
jdbc事务
jdbc的事务操作主要由java.sql.Connection类处理。
有三个方法:
- setAutoCommit(boolean) 是否自动提交
- rollback() 回滚
- commit() 提交
传统的jdbc的操作:
(1)驱动注册
(2)获取链接Connection
(3)statement预编译sql
(4)执行sql
(5)处理结果集
(6)处理异常回滚并释放资源
(7)释放结果集
(8)释放statement
(9)事务提交
(10)释放链接
优缺点:
API简单,可以实现基本的事务功能;
局限于与一个数据库链接,不能涉及到多个数据库,
JTA事务
不是很了解,等待后续的更新
容器事务
容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现。有EJB和spring,主要了解spring事务。
spring并不直接管理事务,而是提供多个事务管理器,将事务的职责委托给相应的平台。
spring框架事务涉及到三个核心接口
PlatformTransactionManager,主要用于管理事务。
TransactionManagerDefinition:事务的定义
TransactionStatus:表示一个事务
//事务的主要方法及参数
TransactionStatus getTransaction(TransactionManagerDefinition);
commit(TransactionStatus);
rollback(TransactionStatus).
事务属性
传播行为,隔离规则,回滚规则,事务超时,是否只读
7种传播行为:
PROPAGATION_REQUIRED:当前没有事务,则创建一个事务,如果已经存在一个事务,则加入其中。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,则以非事务的方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果没有事务,则抛出异常
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,则挂起
PROPAGATION_NOT_SUPPORTS:以非事务方式执行,如果存在事务,将当前事务挂起
PROPAGATION_NEVER:以事务执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED:如果存在事务,则创建一个事务,并嵌套进去,如果不存在事务,则创建事务执行。
spring默认required.常用1,4级别
隔离级别
隔离级别是为应对多个事务,多个事务的并发可能会出现以下问题:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
注:
不可重复读和幻读都是重复查询时出现问题,但是不一样的是,不可重复读更注重的是查询的数据数量不变,但是数据变了;幻读则是第二次查询发现查询出的行数发现了变化,数据行数变化,原数据的数据没变。
spring的隔离级别选择
ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别。
使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。
ISOLATION_READ_UNCOMMITTED:读取为提交的内容。最低隔离级别,允许其他事务读取其他未提交事务的数据。
可能造成脏读,不可重复读,幻读。
ISOLATION_READ_COMMITTED:读取提交的内容。保证一个事务只能在其他事务提交之后才能读取,
可以避免脏读,但是不能避免不可重复读和幻读。
ISOLATION_ISOLATION_REPEATABLE_READ:可重读。这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。
可避免脏读和不可重复读,但是可能出现幻读。
ISOLATION_SERIALIZABLE:可串行化。这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
避免所有的问题
spring的事务配置:
两种方式:
1.编程式事务:通过编写代码实现事务管理,包括事务的开始、提交、回滚。
2.声明式事务:通过aop技术来实现事务管理,将事务管理织入到业务目标中。主要使用。
编程式事务可使用spring提供的事务模板类 transactionTemplate。执行execute()方法,在参数的内部实现中编写逻辑代码。
也可以自定义TransactionDefinition,然后通过PlatformTransactionManager获取TransactionStatus,使用PlatformTransactionManager来实现提交和回滚。
不推荐,代码耦合性太高。
声明式事务主要xml配置和注解配置
基于xml:
spring2.0以后,提供了tx命名空间来配置事务。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- tx:method的属性:
* name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符
(*)可以用来指定一批关联到相同的事务属性的方法。
如:'get*'、'handle*'、'on*Event'等等.
* propagation:不是必须的,默认值是REQUIRED表示事务传播行为,
包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
* isolation:不是必须的 默认值DEFAULT ,表示事务隔离级别(数据库的隔离级别)
* timeout:不是必须的 默认值-1(永不超时),表示事务超时的时间(以秒为单位)
* read-only:不是必须的 默认值false不是只读的表示事务是否只读?
* rollback-for: 不是必须的表示将被触发进行回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
* no-rollback-for:不是必须的表示不被触发进行回滚的 Exception(s),以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
-->
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" rollback-for="Exception"/>
<!-- 其他的方法之只读的 -->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="point"/>
<aop:advisor advice-ref="txAdvice" proint-ref="point"/>
</aop:config>
基于注解:
需要在xml配置文件中,开启注解处理器< context:annotation-config/>,同时注册事务管理驱动器< tx:annotation-driver transaction-manager=""/>
@Transactional(
readOnly = false, //读写事务
timeout = -1 , //事务的超时时间,-1为无限制
noRollbackFor = ArithmeticException.class, //遇到指定的异常不回滚
isolation = Isolation.DEFAULT, //事务的隔离级别,此处使用后端数据库的默认隔离级别
propagation = Propagation.REQUIRED //事务的传播行为
)
参考原文:
mysql的隔离级别:
Java事务
编程式事务:
事务百科: