Spring 事务与事务抽象,java 多线程面试总结
}
从代码中我们可以看出来 JDBC 事务的缺点:
1.冗长、重复 2.需要显示事务控制 3.需要显示处理受检查异常
并且 JDBC 仅仅是为了完成事务操作提供了基础的 API 支持,通过操作 JDBC 我们可以将多个 sql 语句放到同一个事务中,保证 ACID 特性,但是当遇到跨库跨表的 sql,简单的 JDBC 事务就无法满足了,基于这种问题,JTA 事务出现了
JTA 事务
JTA(Java Transaction API)提供了跨数据库连接(或其他 JTA 资源)的事务管理能力。JTA 事务管理则由 JTA 容器实现,J2ee 框架中事务管理器与应用程序,资源管理器,以及应用服务器之间的事务通讯
JTA 的构成
在 JTA 中有几个重要的概念:
1).高层应用事务界定接口,供事务客户界定事务边界
2).X/Open XA 协议(资源之间的一种标准化的接口)的标准 Java 映射 ,它可以使事务性的资源管理器参与由外部事务管理器控制的事务中
3).高层事务管理器接口,允许应用程序为其管理的程序界定事务的边界范围
JTA 中的重要接口
JTA 中的重要接口主要位于 javax.transaction 包中
1).UserTransaction
:让应用程序得以控制事务的开始、挂起、提交与回滚等操作,由 java 或者 ejb 组件调用
2).TransactionManager
:用于应用服务管理事务的状态
3).Transaction
:用于控制执行事务操作
4).XAResource
:用于在分布式事务环境下,协调事务管理器和资源管理器的工作
5).XID
:用来为事务标示的 java 映射 id
需要注意的是前三个接口仅存在于 javaee.jar 中,在 javaSe 中并不存在。
JTA 事务编程的基本步骤
我们来看下使用 JTA 事务的基本步骤,通过简单的 java 编码完成一个简单的 JTA 事务过程:
//配置 JTA 事务,建立对应的数据源//1.建立事务:通过创建 UserTransac
tion 类的实例来开始一个事务 Context ctx = new InitialContext(p) ;UserTransaction trans = (UserTransaction) ctx.lookup("javax. Transaction.UserTransaction");//开始事务 trans.begin();//找到数据源,进行绑定 DataSource ds = (DataSource) ctx.lookup("mysqldb");//建立数据库连接 Connection mycon = ds.getConnection();//执行了 sql 操作 stmt.executeUpdate(sqlS);//提交事务 trans.commit();//关闭连接 mycon.close();
JTA 事务的优缺点
可以看出,JTA 的优点很明显,提供了分布式下的事务解决方案,并且执行严格的 ACID 操作,但是,标准的 JTA 事务在日常开发中并不常用,其原因就是 JTA 的缺点导致的,例如 JTA 的实现相当复杂,JTA UserTransaction 需要从 JNDI 获取,即我们如果要实现 JTA 一般情况下也需要实现 JNDI,并且 JTA 只是个简易的容器,使用复杂,在灵活的需求下很难实现代码复用,因此我们需要一个能给我们进行完善容器事务操作的框架
Spring 事务与事务抽象
Spring 给我们封装了一套事务机制,并且提供了完善的事务抽象,将事务所需要的步骤进行抽象划分,并以编程的方式提供一个标准 API,如下:
try{
//1.开启事务//2.执行数据库操作
//3.提交事务
}catch(Exception ex){
//处理异常//4.回滚事务
}finally{
//关闭连接,资源清理}
Spring 的事务抽象
Spring 的抽象事务模型基于接口 PlatformTransactionManager ,该接口有不同的多种实现,每一种实现都有对应的一个特定的数据访问技术,大体如下:
可以看到,Spring 并不是提供了完整的事务操作 Api,而是提供了多种事务管理器,将事务的职责托管给了 Hibernate、JTA 等持久化机制平台框架来实现,而仅仅提供一个通用的事务管理器接口--org.springframework.transaction.PlatformTransactionManager ,并且给各大持久化事务平台框架提供了对应的事务管理器,用来限制其通用行为,但是具体事务实现将由各大平台自己去实现:
Public interface PlatformTransactionManager{
// 由 TransactionDefinition 得到 TransactionStatus 对象 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;// 提交 Void commit(TransactionStatus status) throws TransactionException;
// 回滚 Void rollback(TransactionStatus status) throws TransactionException;
}
在 Spring 中使用各个事务
接下来我们来看看,如果使用 Spring 事务抽象来使用各个事务平台,该如何使用:
Spring JDBC 事务
如果应用程序中直接使用 JDBC 来进行持久化操作,可以使用DataSourceTransactionManager
来处理事务边界,而使用DataSourceTransactionManager
,你需要使用 xml 配置将其装配到应用上下文中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean>
而配置完毕以后,在 JDBC 实例中,DataSourceTransactionManager
是通过调用 java.sql.Connection 来管理事务 ,在 sql 所在的方法执行完毕以后,将会自动调用连接的 commit()方法来提交事务,同样的如果执行过程中出现了异常,将会触发调用 rollback()方法进行回滚 。
Hibernate 事务
如果应用程序的持久化是通过 Hibernate 来实现的,那么你需要使用HibernateTransactionManager
,对于 Hibernate3 及以上版本,需要在 Spring 上下文定义中添加如下的 Bean 声明:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean>
Java 持久化 Api 事务--JPA
事实上 JPA 规范的实现来自 Hibernate,如果你打算使用 JPA 事务的话,你需要使用JpaTransactionManager
来管理事务,配置如下:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean>
JpaTransactionManager
只需要装配一个 JPA 实体管理工厂(javax.persistence.EntityManagerFactory 接口的任意实现),而JpaTransactionManager
将与由工厂所产生的 JPA EntityManager 合作来构建事务
PlatformTransactionManager 及其相关属性
事务管理器接口PlatformTransactionManager
通过 getTransaction 方法来得到事务,参数为TransactionDefinition
类,而这个类定义类事务的基本属性:
1.传播行为
2.隔离规则 3.回滚规则 4.事务超时设置 5.事务是否只读
而 TransactionDefinition 接口的定义如下:
public interface TransactionDefinition {int getPropagationBehavior(); // 返回事务的传播行为 int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据 int getTimeout(); // 返回事务必须在多少秒内完成 boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的}
其中最重要的是事务的传播行为以及隔离规则,我们先来看看事务的七种传播行为,如表格所示:
注:虽然有七种,但是其中三种都是 Spring 迭代留下的,一般我们只会配置 REQUIRED 和第四种 REQUIRES_NEW
事务隔离级别
在看事务隔离级别前我们先来看看如果不进行事务隔离,所产生的脏读
、不可重复读
、幻读
效应是什么
脏读
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务获取数据进行操作,结果将刚刚未提交的数据获取到了
不可重复读
不可重复读是指在一个事务内,多次读同一数据,前后读取的结果不一致。在 A 事务还没有结束时,另外一个事务 B 也访问该同一数据。那么,在 A 事务中的两 次读数据的过程中,由于 B 事务对当前数据进行修改操作,导致 A 事务两次读取的数据不一致,因此称为是不 可重复读。
幻读
幻读是指当事务不是独立执行时发生的一种现象,例如 A 事务对表中的一个数据进行了修改,这种修改涉及到表中的全部数据行。 同时,B 事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,就会发生操作 A 事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。
为了解决这些问题,Spring 将事务分为了五个隔离级别,每个隔离级别分别对应的效果如下:
注意:一般建议开启READ_COMMITTED
级别,即只读已经提交的数据,至于不可重复读和幻读问题,可以通过数据库乐观锁版本号方式解决
喜欢本文,可以关注我们的官方账号,第一时间获取资讯。你的关注是对我们更新最大的动力哦~
如果你的技术提升遇到瓶颈了,或者缺高级 Android 进阶视频学习提升自己,这有大量大厂面试题为你面试做准备!后台私信回复:“Android 学习”,“面试文档”,“视频收集大整理”获取。
关注微信公众号“享学课堂 online”获取更多资讯,并且免费获取“面试”资料和更多往期课件资料哦~
评论