前言
在JavaEE企业级开发的应用领域,为了保证数据的完整性和一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。 事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么都不执行。
在上篇笔记中已经介绍事务的四个关键属性:
1.原子性
2.一致性
3.隔离性
4.持久性
一、Spring事务管理
1.之前的方式:编程式事务管理
即:使用原生的JDBC API进行事务管理
步骤:
- 获取数据库连接Connection对象
- 取消事务的自动提交
- 执行操作
- 正常完成操作时手动提交事务
- 执行失败时回滚事务
- 关闭相关资源
该管理方式的缺点
使用原生的JDBC API实现事务管理是所有事务管理方式的基石,同时也是最典型的编程式事务管理。
编程式事务管理需要将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。在使用编程的方式管理事务时,必须在每个事务操作中包含额外的事务管理代码。
相对于核心业务而言,事务管理的代码显然属于非核心业务,如果多个模块都使用同样模式的代码进行事务管理,显然会造成较大程度的代码冗余。
2.现在的方式:声明式事务管理
原因:
大多数情况下声明式事务比编程式事务管理更好:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
事务管理代码的固定模式作为一种横切关注点,可以通过AOP方法模块化,进而借助Spring AOP框架实现声明式事务管理。
Spring在不同的事务管理API之上定义了一个抽象层,通过配置的方式使其生效,从而让应用程序开发人员不必了解事务管理API的底层实现细节,就可以使用Spring的事务管理机制。
- Spring既支持编程式事务管理,也支持声明式的事务管理。
Spring提供的事务管理器:
Spring从不同的事务管理API中抽象出了一整套事务管理机制,让事务管理代码从特定的事务技术中独立出来。开发人员通过配置的方式进行事务管理,而不必了解其底层是如何实现的。
Spring的核心事务管理抽象是PlatformTransactionManager
。它为事务管理封装了一组独立于技术的方法。无论使用Spring的哪种事务管理策略(编程式或声明式),事务管理器都是必须的。
事务管理器可以以普通的bean的形式声明在Spring IOC容器中。
二、XML事务管理
XML 方式配置事务分三步:
① 配置切入点表达式;
② 配置通知与事务参数;
③ 将切入点表达式与通知联系起来
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.oneby"/>
<!-- 引用外部属性文件来配置数据库连接池 -->
<!-- 指定 properties 属性文件的位置,classpath:xxx 表示属性文件位于类路径下 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 从properties属性文件中引入属性值 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${prop.userName}"/>
<property name="password" value="${prop.password}"/>
<property name="url" value="${prop.url}"/>
<property name="driverClassName" value="${prop.driverClass}"/>
</bean>
<!-- 配置 JdbcTemplate 对象,并注入 dataSource 数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理器(注意:bean 的 id 属性一定要是 transactionManager) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 1.配置切入点表达式 -->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.oneby.service.AccountService.*(..))"/>
</aop:config>
<!-- 2.配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务参数 -->
<tx:attributes>
<!-- name 属性指明在哪些方法上设置事务,其他属性可以配置事务参数 -->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 3.将切入点表达式和通知联系起来 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
测试代码:
public class SpringTest {
@Test
public void test() {
//1.创建IOC容器对象
ApplicationContext iocContainer =
new ClassPathXmlApplicationContext("xml-transaction-config.xml");
//2.获取AccountService对象
AccountService accountService = iocContainer.getBean(AccountService.class);
//3.执行数据库操作
accountService.transfer("Heygo", "Oneby", 100);
}
}
总结
对事务管理相关内容的基础补充。