Spring Boot教程之十六:使用 @Transactional 注释进行事务管理

Spring Boot – 使用 @Transactional 注释进行事务管理

@Transactional注释是用于管理 Spring Boot 应用程序中的事务的元数据。要配置Spring Transaction,可以在类级别或方法级别应用此注释。在企业应用程序中,事务是应用程序执行的一系列操作,这些操作一起流水线执行单个操作。例如,预订机票也是一项交易,最终用户必须输入其信息,然后付款才能预订机票。

为什么我们需要事务管理?

让我们通过上面的例子来理解交易,如果用户输入了他的信息,那么用户的信息就会存储在 user_info 表中。现在,为了订票,他进行了在线支付,但由于某种原因(系统故障),付款被取消了,所以他没有订票。但是,问题是他的信息存储在 user_info 表中。从大范围来看,一天内会发生数千件这样的事情。因此,存储交易的单个操作并不是一个好的做法(这里只存储用户信息,而不存储支付信息)。

为了克服这些问题,spring 提供了事务管理,它使用注释来处理这些问题。在这种情况下,spring 将用户信息存储在临时内存中,然后检查付款信息,如果付款成功,则它将完成事务,否则它将回滚事务,并且用户信息将不会存储在数据库中。

@Transactional 注解

在 Spring Boot 中,@Transactional 注释用于管理 Spring Boot 应用程序中的事务,并用于定义事务的范围。此注释可应用于类级别或方法级别。它提供数据可靠性和一致性。当使用 @Transactional 注释指示方法时,它表示应在该事务的上下文中执行特定方法。如果事务成功,则提交对数据库所做的更改,如果任何事务失败,则对该特定事务所做的所有更改都可以回滚,这将确保数据库保持一致状态。

注意:要使用@Transactional注释,您需要使用@EnableTransactionManagement在Spring Boot应用程序的主类中配置事务管理。

在 Spring Boot 中配置事务

在这个例子中,我们将创建一个应用程序来存储用户信息及其地址信息,并将使用 spring 事务管理来解决事务中断问题。

注释@Transactional允许您以声明方式定义事务边界。对于那些希望加深对 Spring Boot 功能的理解的人来说,Java Backend课程涵盖了保护应用程序的基本安全实践。

事务管理的逐步实施

步骤1:创建Spring Boot项目

在此步骤中,我们将创建一个 Spring Boot 项目。为此,我们将使用Spring Initializr

第 2 步:添加依赖项

我们将为我们的 Spring Boot 应用程序添加所需的依赖项。

步骤3:配置数据库

现在,我们将在应用程序中配置数据库。我们将使用以下配置并将其添加到我们的application.properties文件中。

server.port = 9090
#database configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employee_db
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
#the ddl-auto=update : It will create the entity schema and map it to db automatically
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

注意:请添加您的数据库用户名和密码以及数据库路径。

步骤4:创建模型类

在此

<think>嗯,用户的问题是关于在Spring多数据源环境下,@Transactional和@Service注解失效的原因及解决方法。我需要先回顾一下之前提供的引用内容,看看有没有相关的信息。 根据引用[1],当使用多数据源时,如果不在@Transactional中指定事务管理器,可能会导致失效,因为Spring默认只能选择一个事务管理器。而引用[2]提到,在事务方法内部调用带有@DS注解的方法时,@DS会失效,因为事务使用的是外层方法的数据源。引用[4]则讨论了同类内部方法调用导致@Transactional失效的问题,因为没有通过代理类调用。引用[5]指出,如果没有为某个数据源配置事务管理器,该数据源的事务就不会回滚。 用户的问题涉及到@Service注解失效,可能是指当服务类没有被正确识别为Spring Bean,或者因为多数据源配置导致Bean的载有问题。比如,如果@Service注解的类没有被正确扫描到,或者被多次定义,可能导致依赖注入失败,进而事务注解也不生效。 首先,我需要整理可能导致@Transactional失效的原因:事务管理器未指定、方法内部调用、异常类型未正确配置、数据源切换与事务管理不协调等。而@Service失效可能涉及组件扫描的问题,或者Bean名称冲突。 对于解决方案,需要分点说明,比如正确配置事务管理器、指定事务管理器名称、避免内部调用、处理异常类型,以及确保@Service的组件扫描正确。同时,结合引用中的例子,比如在@Transactional中指定transactionManager属性,或者在配置类中显式定义Bean。 可能还需要提到动态数据源的情况下,如何配合@DS注解使用,确保事务管理器和数据源匹配。另外,检查Spring的代理机制,确保AOP能够拦截到带有注解的方法,避免自调用问题。 用户可能需要具体的代码示例,比如如何在配置类中定义多个事务管理器,如何在Service层正确使用注解,以及如何排除组件扫描的冲突。需要确保回答结构清晰,分点列出原因和对应的解决方法,并引用相关的引用资料作为支持。</think>### 多数据源环境下@Transactional和@Service注解失效的原因及解决方案 #### 一、@Transactional注解失效原因及解决 **1. 事务管理器未正确指定** - **原因**:多数据源需为每个数据源单独配置事务管理器。默认情况下,Spring使用一个默认事务管理器(如未显式指定),导致其他数据源的事务不生效[^1][^5]。 - **解决**:在`@Transactional`中显式指定事务管理器名称。例如: ```java @Transactional(transactionManager = "oracleTransactionManager") public void oracleOperation() { ... } ``` **2. 方法内部调用导致代理失效** - **原因**:Spring通过代理实现事务管理,若在非事务方法A中调用同类的事务方法B,代理无法拦截方法B,导致事务失效[^4]。 - **解决**: - 将事务方法B抽取到另一个类中,通过注入调用。 - 使用`AopContext.currentProxy()`获取代理对象调用方法B(需开启`@EnableAspectJAutoProxy(exposeProxy = true)`)。 **3. 数据源切换与事务管理不协调** - **原因**:若使用动态数据源(如`@DS`注解),事务中数据源会被提前绑定到事务管理器,导致内部方法无法切换数据源[^2]。 - **解决**: - 确保事务方法外层已明确指定事务管理器及数据源。 - 避免在事务方法内部调用其他数据源的操作(需拆分事务边界)。 **4. 异常类型未正确声明** - **原因**:默认`@Transactional`仅回滚`RuntimeException`,若抛出其他异常(如`Exception`)需显式声明`rollbackFor`[^3][^4]。 - **解决**:明确指定回滚异常类型: ```java @Transactional(rollbackFor = Exception.class, transactionManager = "mysqlTransactionManager") ``` --- #### 二、@Service注解失效原因及解决 **1. 组件扫描路径冲突** - **原因**:多数据源配置中可能因包扫描重叠导致Bean重复注册,或未正确扫描到Service类。 - **解决**: - 检查`@ComponentScan`路径,确保Service类所在包被正确扫描。 - 避免多个配置类重复扫描同一包。 **2. 数据源配置类干扰** - **原因**:若手动配置数据源或`SqlSessionFactory`,未正确关联`@MapperScan`或`@EntityScan`,导致Service依赖注入失败。 - **解决**: - 在数据源配置类中指定`@MapperScan(basePackages = "com.example.mapper", sqlSessionFactoryRef = "mysqlSqlSessionFactory")`。 - 确保Service类未被排除在Spring容器外(如错误的`exclude`过滤)。 --- #### 三、完整配置示例 **1. 多数据源及事务管理器配置** ```java @Configuration public class DataSourceConfig { // 主数据源(MySQL) @Bean @ConfigurationProperties(prefix = "spring.datasource.mysql") public DataSource mysqlDataSource() { return DataSourceBuilder.create().build(); } @Bean public PlatformTransactionManager mysqlTransactionManager() { return new DataSourceTransactionManager(mysqlDataSource()); } // 从数据源(Oracle) @Bean @ConfigurationProperties(prefix = "spring.datasource.oracle") public DataSource oracleDataSource() { return DataSourceBuilder.create().build(); } @Bean public PlatformTransactionManager oracleTransactionManager() { return new DataSourceTransactionManager(oracleDataSource()); } } ``` **2. Service层正确用法** ```java @Service public class UserService { @Autowired private OracleDao oracleDao; // 显式指定事务管理@Transactional(transactionManager = "oracleTransactionManager") public void saveOracleData(User user) { oracleDao.insert(user); } } ``` --- ### 相关问题 1. 如何动态切换Spring多数据源? 2. 在Spring Boot中如何避免事务嵌套导致的数据源冲突? 3. 多数据源环境下如何实现分布式事务?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潜洋

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值