Spring 的声明式事务管理是建立在 Spring AOP 机制之上的,其本质是对目标方法前后进行拦截,并在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中作相关的事务规则声明(或通过等价的基于标注的方式),便可以将事务规则应用到业务逻辑中。总的来说,声明式事务得益于 Spring IoC容器 和 Spring AOP 机制的支持:IoC容器为声明式事务管理提供了基础设施,使得 Bean 对于 Spring 框架而言是可管理的;而由于事务管理本身就是一个典型的横切逻辑(正是 AOP 的用武之地),因此 Spring AOP 机制是声明式事务管理的直接实现者。
显然,声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要在XML文件中配置或者添加注解就可以获得完全的事务支持。因此,通常情况下在开发中使用声明式事务,不仅因为其简单,更主要是因为这样使得纯业务代码不被污染,极大方便后期的代码维护
Spring中的声明式事务管理可以通过两种方式来实现,一是基于XML的方式,而是基于注解的方式
打开mysql,创建一张user
表
CREATE TABLE user(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (ID)
);
创建一个maven工程【Spring】Spring入门案例
在pom.xml
中加入Spring
、aop
和mysql
相关的包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
<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 https://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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.lucas"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.cj.jdbc.Driver">property>
<property name="url"
value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true">property>
<property name="username" value="root">property>
<property name="password" value="123456">property>
bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="advice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.lucas.*.*())" id="tx"/>
<aop:advisor advice-ref="advice" pointcut-ref="tx"/>
aop:config>
beans>
添加数据库操作
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository("userTransaction")
public class UserTransaction {
@Autowired
private JdbcTemplate jdbcTemplate;
public void updateUser() {
String sql = "insert into user values (?,?,?)";
String sql1 = "insert into user values (?,?,?)";
Object[] para = {1, "张三", 21};
jdbcTemplate.update("delete from user");
jdbcTemplate.update(sql, para);
jdbcTemplate.update(sql1, para);
}
}
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserTransaction userTransaction = (UserTransaction) applicationContext.getBean("userTransaction");
userTransaction.updateUser();
}
}
运行结果:
从执行的结果来看,由于发生异常导致代码回滚,数据库中并没有插入数据
修改spring配置文件
<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 https://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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.lucas"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.cj.jdbc.Driver">property>
<property name="url"
value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true">property>
<property name="username" value="root">property>
<property name="password" value="123456">property>
bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:annotation-driven transaction-manager="txManager"/>
beans>
加上spring事务管理注解
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository("userTransaction")
//该注解指定该类所有的方法都需要受Spring事务的管理 该注解也可以添加在方法上 仅对 public 方法有效
@Transactional
public class UserTransaction {
@Autowired
private JdbcTemplate jdbcTemplate;
public void updateUser() {
String sql = "insert into user values (?,?,?)";
String sql1 = "insert into user values (?,?,?)";
Object[] para = {1, "张三", 21};
jdbcTemplate.update("delete from user");
jdbcTemplate.update(sql, para);
jdbcTemplate.update(sql1, para);
}
}
执行结果同上