在JavaEE企业级开发的应用领域,为了保证数据的完整性和一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。
事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么都不执行。
事务的四个关键属性(ACID)
@Target({ ElementType.METHOD, ElementType.TYPE }) 可以标注在类上,以及方法上
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
propagation属性:事务的传播行为,一个事务方法被另外一个事务方法调用时,当前的事务如何使用事务.,属性的内容主要先择在一下的Propagation的枚举类中
public enum Propagation {
/**支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/**支持当前事务,如果当前没有事务,就以非事务方式执行*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/**支持当前事务,如果当前没有事务,就抛出异常*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/**新建事务,如果当前存在事务,把当前事务挂起*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/**-以非事务方式执行操作,如果当前存在事务,就把当前事务挂起*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**以非事务方式执行,如果当前存在事务,则抛出异常*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/**如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。
* 它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。
* 内部事务的回滚不会对外部事务造成影响。
* 它只对DataSourceTransactionManager事务管理器起效
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
isolation属性:事务的隔离级别,I也在org.springframework.transaction.annotation.Isolation枚举类中
public enum Isolation {
/**数据库的默认级别*/
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
/**读未提交 脏读*/
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
/**读已提交 不可重复读(update)*/
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
/**可重复读 幻读(插入操作)*/
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
/** 串行化 效率低*/
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
private final int value;
Isolation(int value) { this.value = value; }
public int value() { return this.value; }
}
timeout:事物的超时时间,设置事务在强制回滚之前可以占用的时间,默认为-1,不超时,单位为s(测试为单位s)
readOnly:是否只读
剩下的四个属性:事务的回滚与不回滚 默认情况下, Spring会对所有的运行时异常进行事务回滚,指定异常的类名,或者类型
Class extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
xml文件,基于注解的形式配置
xml文件,基于方法名的形式配置
在springboot中,可以使用@EnableTransactionManagement注解开启事务,
有的事物是自动装配的,例如mybatis,会依赖spring-jdbc
spring-jdbc,会自动装配事务的解析器,有兴趣的,可以直接看下org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration.class以及org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.class的源代码,就可以了,部分源码
@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider>> customizers) {
return new TransactionManagerCustomizers(customizers.getIfAvailable());
}
@Configuration
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
private final PlatformTransactionManager transactionManager;
public TransactionTemplateConfiguration(
PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Bean
@ConditionalOnMissingBean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(this.transactionManager);
}
}
@Configuration
@ConditionalOnBean(PlatformTransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
@Configuration
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
}
@Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
static class DataSourceTransactionManagerConfiguration {
private final DataSource dataSource;
private final TransactionManagerCustomizers transactionManagerCustomizers;
DataSourceTransactionManagerConfiguration(DataSource dataSource,
ObjectProvider transactionManagerCustomizers) {
this.dataSource = dataSource;
this.transactionManagerCustomizers = transactionManagerCustomizers
.getIfAvailable();
}
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public DataSourceTransactionManager transactionManager(
DataSourceProperties properties) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
this.dataSource);
if (this.transactionManagerCustomizers != null) {
this.transactionManagerCustomizers.customize(transactionManager);
}
return transactionManager;
}
}
}