事务(终极总结)
什么是事务:一组原子操作。数据库层面来看,指一组sql指令。
事务有什么用:用来控制数据安全。
事务发展:
1、最先的事务指的是数据库事务,指一组sql指令,如果一个执行失败则全部会滚。
2、java事务指:由于java程序是通过jdbc操作数据库的(insert、delete、update)因此慢慢习惯称数据库事务为java事务
4大特性
1、原子性:体现一个事务的操作的不可分割,要么权执行,要么全不执行。
2、一致性:事务的执行结果必须从一种一致性状态变到另一种一致性状态。最典型的就是转账,两个账户A、B总金额为5000,不管A、B如何转账,转几次,当事务结束A、B账户总金额还为5000。
3、隔离性:即并发执行的事务操作同一张表时相互之间不能相互影响。举例说明就是对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,不能出现交叉执行。
4、持久性:指事务一旦被提交,对数据库中数据的改变时永久性的。
java事务
JDBC和JTA事务区别 简单的说 JTA是多库的事务 JDBC是单库的事务
1、JTA(Java Transcation Api ):
JTA的事务周期可横跨多个JDBC Connection生命周期,对众多Connection进行调度,实现其事务性要求。
2、jdbc事务:
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
3、容器事务
常见的容器事务如Spring事务,容器事务大多是基于JTA完成
事务传播特性
解决事务创建时机的问题
PROPAGATION_REQUIRED:如果上下文中已经存在事务,那么就加入到事务中执行;如果当前上下文中不存在事务,则新建事务执行。spring 默认
PROPAGATION_SUPPORTS:如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行
PROPAGATION_MANDATORY:该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别
PROPAGATION_REQUIRES_NEW:每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行
PROPAGATION_NOT_SUPPORTED:若上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务
PROPAGATION_NEVER:上下文中不能存在事务,一旦有事务,就抛出runtime异常
PROPAGATION_NESTED:如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务
事务的隔离性
级别越高相对性能越查。
1、SERIALIZABLE:可避免脏读、不可重复读、幻读的发生
2、REPEATABLE_READ:可避免脏读、不可重复读的发生(MySQL InnoDB默认、注)
3、READ_COMMITTED:可避免脏读的发生(大部分数据库默认: SqlServer、Oracle)
4、READ_UNCOMMITTED:最低级别,任何情况都无法保证
隔离级别所解决的问题
1、脏读:一个事务读取了另一个事务还未提交的数据,这里主要指事务读取了另一个事务未回滚前的数据。
2、不可重读:不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值。例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,此时发生了不可重复读。
3、幻读:指事务a根据一定条件查询一些数据并且做修改,这时事务b插入了一条数据,事务a执行完毕后,再次查询符合条件的工单时,发现有一条数据没有被修改。
总结:不可重读与幻读的区别是,不可重读针对一条数据,幻读针对的是多条。都是读取了commit后的事务发生的错误。而脏读是因为读取了没有commit事务导致的错误
spring事务配置
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 切面中这些名称开头的方法拥有对应传播特性 -->
<tx:method name="add*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="modify*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="remove*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="del*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="set*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="update*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="query*" propagation="REQUIRED" read-only="true"/>
<tx:method name="putQueue*" propagation="REQUIRED"/>
<tx:method name="http*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<!-- 切面 -->
<aop:pointcut id="txPointcut" expression="execution(* com.xes.stone.complaint.core.service.impl.*.*(..))" />
<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice" />
</aop:config>