public interface PlatformTransactionManager {
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
}
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
}
| 传播性 | 值 | 描述 | 备注 |
|---|---|---|---|
| PROPAGATION_REQUIRED | 0 | 当前事务有就用当前的,没有就用新的 | 默认 |
| PROPAGATION_SUPPORTS | 1 | 事务可有可无,非必须 | |
| PROPAGATION_MANDATORY | 2 | 当前一定要有事务,否则就抛异常 | |
| PROPAGATION_REQUIRES_NEW | 3 | 无论是否有事务,都另起一个新的事务 | 会把旧事务挂起 |
| PROPAGATION_NOT_SUPPORTED | 4 | 不支持事务,按非事务方式运行 | |
| PROPAGATION_NEVER | 5 | 不支持事务,如果有事务就抛出异常 | |
| PROPAGATION_NESTED | 6 | 当前有事务就在当前事务再起一个事务 | 1. 里面的事务拥有独立的属性,如回滚状态 2. 里面的事务回滚并不会影响外面的事务 |
| 隔离性 | 值 | 脏读 | 不可重复读 | 幻读 | 备注 |
|---|---|---|---|---|---|
| ISOLATION_DEFAULT | -1 | 取决于数据库配置 | |||
| ISOLATION_READ_UNCOMMITTED | 1 | Y | Y | Y | |
| ISOLATION_READ_COMMITTED | 2 | Y | Y | ||
| ISOLATION_REPEATABLE_READ | 4 | Y | |||
| ISOLATION_SERIALIZABLE | 8 |
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
CREATE TABLE PERSON
(
ID BIGINT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255)
);
INSERT INTO PERSON (ID, NAME) VALUES ('1', 'zhongmingmao');
@Slf4j
@SpringBootApplication
public class ProgrammaticTransactionApplication implements CommandLineRunner {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
public static void main(String[] args) {
SpringApplication.run(ProgrammaticTransactionApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
log.info("COUNT BEFORE TRANSACTION : {}", getCount());
transactionTemplate.execute(status -> {
jdbcTemplate.update("INSERT INTO PERSON (NAME) VALUES ('A')");
log.info("COUNT IN TRANSACTION : {}", getCount());
status.setRollbackOnly();
return null;
});
log.info("COUNT AFTER TRANSACTION : {}", getCount());
// 输出
// COUNT BEFORE TRANSACTION : 1
// COUNT IN TRANSACTION : 2
// COUNT AFTER TRANSACTION : 1
}
private long getCount() {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM PERSON", Long.class);
}
}
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean{
}
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
private int propagationBehavior = PROPAGATION_REQUIRED;
private int isolationLevel = ISOLATION_DEFAULT; // -1
private int timeout = TIMEOUT_DEFAULT; // -1
private boolean readOnly = false;
}
由于@EnableTransactionManagement的mode默认值为 PROXY ,PROXY对应的是 JDK动态代理 (基于 接口 )
public interface PersonService {
void insert();
void insertThenRollback();
void invokeInsertThenRollback();
}
@Component
public class PersonServiceImpl implements PersonService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
@Transactional
public void insert() {
jdbcTemplate.update("INSERT INTO PERSON (NAME) VALUES ('A')");
}
@Override
@Transactional(rollbackFor = UnexpectedRollbackException.class)
public void insertThenRollback() {
jdbcTemplate.update("INSERT INTO PERSON (NAME) VALUES ('A')");
throw new UnexpectedRollbackException("Just For Test");
}
@Override
public void invokeInsertThenRollback() {
// 方法的内部调用,没有走到增强的代理类上,因此也没有事务支持(实际是使用了数据库的隐式事务,自动提交)
// 不会回滚!!
insertThenRollback();
}
}
@Slf4j
@SpringBootApplication
public class DeclarativeTransactionApplication implements CommandLineRunner {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private PersonService personService;
public static void main(String[] args) {
SpringApplication.run(DeclarativeTransactionApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
personService.insert();
log.info("insert, count : {}", getCount());
try {
personService.insertThenRollback();
} catch (Throwable throwable) {
log.info("insertThenRollback, count : {}", getCount());
}
try {
personService.invokeInsertThenRollback();
} catch (Throwable throwable) {
log.info("invokeInsertThenRollback, count : {}", getCount());
}
// 输出
// insert, count : 2
// insertThenRollback, count : 2
// invokeInsertThenRollback, count : 3
}
private long getCount() {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM PERSON", Long.class);
}
}