Spring JDBC与事务管理(三)

简介: Spring JDBC与事务管理

二.Spring编程式事务


从本节开始,我们来了解一下Spring JDBC中如何进行事务管理。


编程式事务:编程式事务,就是指通过代码手动提交回滚的事务控制方法。Spring JDBC通过TransactionManager事务管理器实现事务控制。事务管理器提供commit/rollback方法进行事务提交与回滚。


下面通过实际的代码,来通过事务管理器来提交和回滚事务。


下面要把10名新员工导入到employee表中。对于这导入的10名新员工,我有一个小要求,要么全部导入成功,要么全部导入失败,什么都不做。

下面新创建一个service包,像上面批量导入的操作是属于业务逻辑中的方法。然后在里面创建EmployeeService类。


package com.haiexijun.service;
import com.haiexijun.dao.EmployeeDao;
import com.haiexijun.entity.Employee;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.Date;
public class EmployeeService {
    private EmployeeDao employeeDao;
    private DataSourceTransactionManager transactionManager;
    //批量插入10名员工
    public void batchImport(){
        //定义了事务默认的标准配置
        TransactionDefinition definition=new DefaultTransactionDefinition();
        TransactionStatus status= transactionManager.getTransaction(definition);
        try {
            //我们用for循环来模拟一下
            for (int i = 1; i < 11; i++) {
                Employee employee = new Employee();
                employee.setEno(8000 + i);
                employee.setEname("员工" + i);
                employee.setSalary(4000f);
                employee.setDname("市场部");
                employee.setHiredate(new Date());
                employeeDao.insert(employee);
            }
            //提交事务
            transactionManager.commit(status);
        }catch (Exception e){
            //回滚事务
            transactionManager.rollback(status);
            throw e;
        }
    }
    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }
    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }
    public DataSourceTransactionManager getTransactionManager() {
        return transactionManager;
    }
    public void setTransactionManager(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
}


还要在applicationContext.xml中对EmployeeService与事务管理器事务管理器进行配置:


    <!--配置EmployeeService-->
    <bean id="employeeService" class="com.haiexijun.service.EmployeeService">
        <property name="employeeDao" ref="employeeDao"/>
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
    <!--编程式事务的配置(配置事务管理器)-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--绑定数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>


这样就算配置好了。


三.Spring声明式事务


声明式事务是指在不修改源代码的情况下通过配置的形式自动实现事务控制,声明式事务的本质就是AOP环绕通知。当目标方法执行成功时,自动提交事务。当目标方法抛出运行时异常时,自动回滚事务。


声明式事务的整个配置过程都是在applicationContext.xml这个配置文件里面来完成的,无需修改源代码。


配置过程:

1.配置TransactionManager事务管理器。

2.配置事务通知与事务属性。有的方法需要使用事务,而有的则不需要使用事务,比如查询事务。我么要根据不同的情况不同配置。

3.为事务通知绑定PointCut切点。PointCut切点用于说明到底是在系统的哪些类的哪些方法上来应用通知呢?PointCut相当于限定了执行范围。


下面还是通过案例来演示声明式事务。还是回到之前的项目,把之前配置编程式事务的代码和配置给删掉,保留原始的批量新增用户的代码。


上面提到过,声明式事务基于AOP的,那就要导入Spring AOP的相关的aspectjweaer依赖。


        <!--aspectjweaer是Spring AOP的底层依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.8.RC2</version>
        </dependency


然后打开applicationContext这个文件,进行声明式事务的配置:

无论是编程式事务还是声明式事务,都要配置transactionManager事务管理器。我们还要添加一段xml命名空间:**xmlns:ts=“http://www.springframework.org/schema/tx”**和真实schema文件的位置:http://www.springframework.org/schema/txhttps://www.springframework.org/schema/context/spring-tx.xsd

tx这个命名空间专用于事务控制。


除了tx以外,我们还要增加aop这个命名空间。xmlns:aop="http://www.springframework.org/schema/aop"和spring aop的schema的真实地址http://www.springframework.org/schema/aophttps://www.springframework.org/schema/context/spring-aop.xsd


下面是注解,bean,ioc,aop,tx事务管理的约束配置:


<?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
        https://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
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>


下面开始事务通知的配置,决定哪些方法使用事务,哪些方法不使用事务:


    <bean id="employeeService" class="com.haiexijun.service.EmployeeService">
        <property name="employeeDao" ref="employeeDao"/>
    </bean>
    <!--声明式事务的配置-->
    <!--1.事务管理器的配置用于 |创建事务、提交事务、回滚事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--2.事务通知配置,决定哪些方法使用事务,哪些方法不使用事务-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--用于设置声明式事务的属性-->
        <tx:attributes>
            <!--说明哪些方法要使用事务,哪些方法不使用事务-->
            <!--name设置要实用事务的方法名,propagation设置事务的传播行为-->
            <!--百分之九十九的情况下propagation都是使用REQUIRED这个参数-->
            <tx:method name="batchImport" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置通知作用在哪些类上(作用范围)-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(public * com.haiexijun.service..*Service.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>


下面对batchImport方法进行改造,制造一个运行时异常。看运行结果:


package com.haiexijun.service;
import com.haiexijun.dao.EmployeeDao;
import com.haiexijun.entity.Employee;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.Date;
public class EmployeeService {
    private EmployeeDao employeeDao;
    //批量插入10名员工
    public void batchImport(){
            for (int i = 1; i < 11; i++) {
                if (i==3){
                    throw new RuntimeException("意料之外的异常");
                }
                Employee employee = new Employee();
                employee.setEno(8000 + i);
                employee.setEname("员工" + i);
                employee.setSalary(4000f);
                employee.setDname("市场部");
                employee.setHiredate(new Date());
                employeeDao.insert(employee);
            }
    }
    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }
    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }
}

d86f27199736435393453ae4b3615312.png

6078d33b1de84cc39d17ba9d41531d2a.png


下面把异常去掉,运行看结果:


467cbadaaebc490fa0a07097e37a1321.png


82535278869b475398d8125a1fe497dd.png


这时候又引发了一个新的问题,作为EmployeeService的方法中只有一个batchImport方法,但是在未来EmployeeService中会有各种各样的方法,难道我们要定义成百上千个<tx:method name=“batchImport” propagation=“REQUIRED”/>来配置哪些方法使用事务吗?其实大可不必,其实作为method的配置他允许进进行通配符映射。如上面的batchImport可以写成batch*,也是一样的效果。那如果对于查询不需要事务,该这么去配置呢?其实也很简单。配置:<tx: method name=“find*” propagation=“NOT_SUPPORTED” read-only=“true”>就可以了。


四.事务传播行为


事务传播行为在我们日常开发中,使用的比较少。

事务传播行为是指多个拥有事务的方法在嵌套调用时的事务控制方式。


e32ae62f2d0f41659e7e57dd8e37f5b7.png


caa3e7af72ab41d59244cf6bb01b8e4b.png


五.注解配置声明式事务


把applicationContext.xml之前的关于声明式事务的配置删除掉,就是如下部分:


    <!--2.事务通知配置,决定哪些方法使用事务,哪些方法不使用事务-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="batchImport" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置通知作用在哪些类上(作用范围)-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(public * com.haiexijun.service..*Service.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>


然后换成注解形式配置声明式事务:

添加如下的代码,就可以了:


<tx:annotation-driven transaction-manager="transactionManager"/>


然后就可以用注解进行配置了。配置声明式事务我们只需要用到@Transactional这一个注解就行了


import java.util.Date;
//声明式事务的核心注解
//放在类上,表示将声明式事务配置于当前类的所有方法中,默认事务传播为REQUIRED,也可以配置propagation属性
//也可以写在方法中,表示只对方法生效。
//如:@Transactional((propagation = Propagation.REQUIRED))等
@Transactional
public class EmployeeService {
·······················
}
相关文章
|
6月前
|
Java 关系型数据库 MySQL
深入解析 @Transactional——Spring 事务管理的核心
本文深入解析了 Spring Boot 中 `@Transactional` 的工作机制、常见陷阱及最佳实践。作为事务管理的核心注解,`@Transactional` 确保数据库操作的原子性,避免数据不一致问题。文章通过示例讲解了其基本用法、默认回滚规则(仅未捕获的运行时异常触发回滚)、因 `try-catch` 或方法访问修饰符不当导致失效的情况,以及数据库引擎对事务的支持要求。最后总结了使用 `@Transactional` 的五大最佳实践,帮助开发者规避常见问题,提升项目稳定性与可靠性。
888 12
|
Java 关系型数据库 数据库
Spring Boot多数据源及事务管理:概念与实战
【4月更文挑战第29天】在复杂的企业级应用中,经常需要访问和管理多个数据源。Spring Boot通过灵活的配置和强大的框架支持,可以轻松实现多数据源的整合及事务管理。本篇博客将探讨如何在Spring Boot中配置多数据源,并详细介绍事务管理的策略和实践。
1236 3
|
11月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
173 2
Spring高手之路25——深入解析事务管理的切面本质
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
348 9
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
Java Spring 开发者
掌握Spring事务管理,打造无缝数据交互——实用技巧大公开!
【8月更文挑战第31天】在企业应用开发中,确保数据一致性和完整性至关重要。Spring框架提供了强大的事务管理机制,包括`@Transactional`注解和编程式事务管理,简化了事务处理。本文深入探讨Spring事务管理的基础知识与高级技巧,涵盖隔离级别、传播行为、超时时间等设置,并介绍如何使用`TransactionTemplate`和`PlatformTransactionManager`进行编程式事务管理。通过合理设计事务范围和选择合适的隔离级别,可以显著提高应用的稳定性和性能。掌握这些技巧,有助于开发者更好地应对复杂业务需求,提升应用质量和可靠性。
164 0
|
Java 数据库连接 API
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
1285 1
|
Java 开发者 Spring
深入解析 @Transactional:Spring 事务管理的艺术及实战应对策略
深入解析 @Transactional:Spring 事务管理的艺术及实战应对策略
176 2
|
设计模式 Java 数据库连接
【Spring源码】JDBC数据源访问实现
我们再来看看阅读线索三,这方面我们从设计模式进行入手。阅读线索三:从这个模块可以学到什么我们看下以下代码,PreparedStatement实例的是由PreparedStatementCreator实现的。再来看看PreparedStatementCreator接口,一共有三个子类实现。也就是说PreparedStatement的三种不同实现被封装到三个子类中,而具体需要哪种实现,只需要传入不同。
150 1
【Spring源码】JDBC数据源访问实现