Spring事务与事务抽象

@Test
public void testTX(){
String url = “jdbc:mysql://127.0.0.1:3306/test”;
String username = “root”;
String password = “1234”;

String sourceUserId = “leo”;
String desUserId = “xnn”;
int money = 500;

Connection connection = null;
try {
//1.加载数据库驱动程序
Class.forName(“com.mysql.jdbc.Driver”);
//获得数据库连接
connection = DriverManager.getConnection(url, username, password);
//开启事务
connection.setAutoCommit(false);//如果为true的话,sql语句会分别执行,修改数据库;如果为false的话,会激活事务

//多条数据操作数据
Statement sql = connection.createStatement();
sql.executeUpdate(“UPDATE user_info SET balance = balance-” + money + " WHERE user_id = ‘" + sourceUserId+"’“);
sql.executeUpdate(“UPDATE user_info SET balance = balance+” + money + " WHERE user_id = '” + desUserId+“'”);
//提交事务
connection.commit();

} catch (SQLException e) {
e.printStackTrace();
try{
//回滚
connection.rollback();
}catch (SQLException ex){
}

} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

从代码中我们可以看出来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.建立事务:通过创建UserTransaction类的实例来开始一个事务
Context ctx = new InitialContext§ ;
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配置将其装配到应用上下文中:

而配置完毕以后,在JDBC实例中,DataSourceTransactionManager是通过调用java.sql.Connection来管理事务 ,在sql所在的方法执行完毕以后,将会自动调用连接的commit()方法来提交事务,同样的如果执行过程中出现了异常,将会触发调用rollback()方法进行回滚 。

Hibernate事务

如果应用程序的持久化是通过Hibernate来实现的,那么你需要使用HibernateTransactionManager ,对于Hibernate3及以上版本,需要在Spring上下文定义中添加如下的Bean声明:

Java持久化Api事务–JPA

事实上JPA规范的实现来自Hibernate,如果你打算使用JPA事务的话,你需要使用JpaTransactionManager 来管理事务,配置如下:

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(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
}

其中最重要的是事务的传播行为以及隔离规则,我们先来看看事务的七种传播行为,如表格所示:

PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_MANDATORY支持当前事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常

最后

在事务,就把当前事务挂起** |
| PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |

最后

[外链图片转存中…(img-snd8T2P5-1718722060263)]

[外链图片转存中…(img-WMhXptfz-1718722060264)]

[外链图片转存中…(img-DfEYwsoL-1718722060264)]

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值