Spring——声明式事务
目录
声明式事务的实现方式
XML配置
配置类配置
混合配置
Spring声明式基于AOP实现,是通过配置注解或xml来管理事务,而不需要在业务代码中像编程式事务那样管理代码。
特性 | 编程式事务 | 声明式事务 |
---|---|---|
代码侵入性 | 强,事务代码与业务代码混合 | 弱,通过配置或注解,代码几乎无侵入 |
控制粒度 | 细粒度,可以精确控制事务边界 | 粗粒度,通常作用于方法级别 |
灵活性 | 高,可以根据条件动态控制事务 | 相对较低,配置固定,但可通过条件表达式等增强 |
可维护性 | 低,事务代码分散在业务代码中 | 高,事务配置集中管理 |
实现方式 | 编写代码,使用PlatformTransactionManager 或TransactionTemplate | 使用注解(如@Transactional )或XML配置 |
底层技术 | 直接使用事务API | 基于Spring AOP和代理机制 |
声明式事务的实现方式
声明式事务可以通过XML或注解配置,也可以混合使用。
XML配置
xml配置声明式有三个步骤:
- 配置事务管理器
- 配置事务通知
- 配置AOP
配置事务管理器:
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"><property name="dataSource" ref="dataSource"/> </bean>
配置事务通知:
配置说明:
事务通知(tx:advice)
id="txAdvice"
:事务通知的唯一标识transaction-manager="transactionManager"
:关联前面定义的事务管理器事务属性(tx:attributes)通过
<tx:method>
定义不同方法的事务规则,支持通配符匹配方法名:
name
:方法名匹配规则(如save*
匹配所有以 save 开头的方法)propagation
:事务传播行为(核心属性)
REQUIRED
:默认值,当前无事务则新建,有则加入REQUIRES_NEW
:强制新建事务,暂停当前事务(若存在)SUPPORTS
:支持事务,无事务则非事务执行isolation
:事务隔离级别(默认DEFAULT
,使用数据库默认)read-only
:是否只读(查询方法设为true
,优化性能)rollback-for
:指定需要回滚的异常(默认仅回滚 RuntimeException)timeout
:事务超时时间(-1 表示无限制)<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes><tx:method name="add*"/><tx:method name="update*"/><tx:method name="delete*"/><tx:method name="insert*"/><tx:method name="transfer*"/></tx:attributes></tx:advice>
配置AOP:
<aop:config><aop:pointcut expression="execution(* com.cc.service.*.*(..))" id="pc"/><aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/></aop:config>
然后编写方法,注意方法名要和配置的方法名对应:
public void update2(){userDao.updateUsernameById(1,"ng");int i = 1/0;}
这样调用该方法,抛异常时就会自动回滚。
配置类配置
首先写一个java配置类来代替spring的配置文件,里面包含了定义事务管理器和mybatis配置:
@Configuration
@ComponentScan("com.cc")
@EnableTransactionManagement
@MapperScan("com.cc.dao")
public class JavaConfig {@BeanDataSource dataSource(){DriverManagerDataSource ds = new DriverManagerDataSource();ds.setDriverClassName("com.mysql.cj.jdbc.Driver");ds.setUrl("jdbc:mysql://localhost:3306/shop-user");ds.setUsername("root");ds.setPassword("123456");return ds;}@BeanPlatformTransactionManager transactionManager(){return new DataSourceTransactionManager(dataSource());}@Beanpublic SqlSessionFactory sqlSessionFactory() throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource());return sessionFactory.getObject();}}
接着在业务方法上面加上注解@Transactional,
@Transactional
public void tr(){userDao.updateUsernameById(1,"ng1n");int i = 1/0;
}
然后用一个main方法区调用,发现事务自动回滚:
public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);UserService2 bean = context.getBean(UserService2.class);bean.tr();}
混合配置
混合配置使用xml+注解的方式,无需使用配置类
XML中的配置:
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/shop-user"/><property name="username" value="root"/><property name="password" value="123456"/>
</bean><bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"><property name="dataSource" ref="dataSource"></property>
</bean><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"><property name="dataSource" ref="dataSource"/>
</bean><!-- 开启注解式事务支持-->
<tx:annotation-driven/>
后面直接使用@Transactional注解即可。