@Transactional
是 Spring 框架提供的一个注解,用于声明一个方法或类需要在事务的上下文中执行。当使用 @Transactional
注解时,Spring 会为该方法或类创建一个代理,该代理会确保方法在执行时处于一个合适的事务边界内。
以下是 @Transactional
注解的一些关键特性和用法:
1. 声明位置
- 可以声明在类级别上,这样该类中的所有公共方法都将使用相同的事务属性。
- 可以声明在方法级别上,这样只有该方法会使用特定的事务属性。
2. 事务属性
propagation
:定义事务的传播行为。例如,Propagation.REQUIRED
表示当前方法必须在事务上下文中运行;如果当前没有事务,就新建一个事务。isolation
:定义事务的隔离级别。例如,Isolation.READ_COMMITTED
意味着一个事务只能读取已经提交的数据。timeout
:定义事务的超时时间。readOnly
:标记事务为只读,以优化性能。rollbackFor
和noRollbackFor
:定义哪些异常会导致事务回滚,以及哪些异常不会。
3. 使用示例
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Transactional
public void methodWithTransactionalAnnotation() {
// ... 方法体 ...
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodWithCustomPropagation() {
// ... 方法体 ...
}
@Transactional(readOnly = true)
public void readOnlyMethod() {
// ... 方法体 ...
}
}
4. 注意事项
@Transactional
注解只能应用于 public 方法上。如果应用于非 public 方法上,Spring 不会创建代理,因此事务管理不会生效。- 当使用代理时,从同一个类中的另一个方法调用注解了
@Transactional
的方法,事务管理不会生效,因为这是在同一个对象内部调用,而不是通过代理调用。要解决这个问题,可以将需要事务管理的方法移到一个新的服务类中,并从那里调用。 - 如果需要在事务中捕获异常并仍然希望事务回滚,应确保重新抛出运行时异常(RuntimeException)或其子类,因为 Spring 默认只在遇到运行时异常时回滚事务。
通过正确使用 @Transactional
注解,你可以确保数据库操作在正确的事务边界内执行,从而提高数据的一致性和可靠性。
在 Maven 的 pom.xml
文件中,为了使用 Spring 的 @Transactional
注解,你需要添加 Spring Framework 的相关依赖。@Transactional
注解是 Spring Framework 的一部分,因此你通常需要添加 Spring Context 的依赖,以及如果你正在使用 Spring Boot,则可能还需要 Spring Boot Starter 的依赖。
以下是一个基本的 Maven 依赖示例,展示了如何添加 Spring Context 的依赖:
<dependencies>
<!-- Spring 集成 mybatis -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- 日志 log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
需要为Spring提供配置文件:
<?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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.sict"/>
<!--配置数据源,连接数据库-->
<bean class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 在Spring配置文件中启用声明式事务管理。使用<tx:annotation-driven />标签来启用对@Transactional注解的支持。-->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--配置sql会话工厂-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis.xml"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
<property name="basePackage" value="com.sict.model.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
上面配置了数据源,.DataSourceTransactionManager 事务管理器,启用对@Transactional注解的支持。当然还有mybatis自己的配置文件classpath:mybatis.xml和mapper映射文件的位置。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sict.model.dao.PersonMapper;
import com.sict.model.vo.Person;
import java.util.List;
@Service
public class PersonService {
@Autowired
private PersonMapper mapper;
public List<Person> showAll() {
return mapper.selectAll();
}
@Transactional
public int insertPerson() {
Person p = new Person(10, "zxg", 20, "1234");
int r = mapper.insertPerson(p);
p = new Person(10, "zxg", 20, "12345678"); // 密码超长,引发异常
r = mapper.insertPerson(p);
return r;
}
@Transactional
public int deletePerson() {
int r = mapper.deletePerson(10);
return r;
}
}
上面insertPerson方法执行2条insert语句,要么都成功,要么都失败。
如果你正在使用 Spring Boot,那么通常会添加 Spring Boot Starter 的依赖,这些 Starter 依赖会自动包含 Spring 框架所需的多个依赖,包括 Spring Context。例如:
<dependencies>
<!-- Spring Boot Starter Data JPA, which includes support for @Transactional -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>YOUR_SPRING_BOOT_VERSION</version>
</dependency>
<!-- Database driver, for example, MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>YOUR_MYSQL_DRIVER_VERSION</version>
</dependency>
<!-- Other dependencies as needed -->
</dependencies>
请将 YOUR_SPRING_BOOT_VERSION
替换为你想要使用的 Spring Boot 版本号。
使用 Spring Boot Starter 依赖时,通常不需要手动添加 Spring Context 或其他基础 Spring 框架的依赖,因为 Starter 会为你自动处理这些依赖关系。
请确保你使用的 Spring 或 Spring Boot 版本与你的项目其他部分兼容,并且符合你的项目需求。你可以访问 Spring 的官方网站或 Maven 中央仓库来查找最新的版本信息。