Spring中的事务控制:
spring中的事务控制分为两种,一种是声明式事务,一种式编程式事务,编程式事务于spring中解耦的核心思想有些冲突,所以实际开发中一般采用声明式事务。
1.前期准备:
开发环境:
IDAD 2.18.3
jdk 1.8
maven 3.5
以及spring所需要的各类jar依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>MySQL</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
既然式用纯注解的方式来编写aop和事务控制,那么我们就应该把相应的配置工具类准备好
先创建一个类,只声明是spring的配置类,打上@Configuration注解等
@ComponentScan( "welness")
@Import({JDBCTemplateConfig.class,TransactionManagerConfig.class})//导入其他的配置类
@Configuration//本类作为spring的配置核心类
@EnableAspectJAutoProxy//开启spring的aop支持
@EnableTransactionManagement//开始spring的注解支持
public class SpringConfiguration {
}
配置切面类
@Component("aspect")//加入spring的容器中
@Aspect//声明此类为切面
public class AspectLogger {
@Pointcut("execution(* welness.service.utils.*.*(..))")
private void pt() {
}
@Around("pt()")
public void printLog(ProceedingJoinPoint pjp) {
/* Object[] args = pjp.getArgs();
Object rtValue = null;*/
try {
System.out.println("开始记录日志");
pjp.proceed();
System.out.println("记录日志成功");
} catch (Throwable throwable) {
System.out.println("事务发生异常,开始回滚");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//这里抛出的是Throwable类型的异常,不是Execption类型的异常,需要手动回滚
throwable.printStackTrace();
}
}
}
这里注意,我在catch代码块里面手动回滚了,因为spring中的事务回滚只有抛出uncheckedExecption以及RuntimeExecption类型的异常才能事务回滚,在环绕通知里面抛出的是Throwable类型的异常,所以自动回滚不能正常进行。
配置事务管理类
PlatformTransactionManager是一个接口,他继承了TransactionManager,提供了对事务的控制
public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager createTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
数据库连接配置
@PropertySource("jdbcConfig.properties")
public class JDBCTemplateConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("jdbcTemplate")
public JdbcTemplate createJdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean("dataSource")
public DataSource createDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
业务层实现类代码
要加上Transactional声明事务的属性
SUPPORTS属性是如果当前有事务,就加入这个事务,如果没有就按无事务的状态进行
REQUIRED属性是如果当前有事务,就按当前事务进行,如果没有事务,就创建一个和事务
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
@Service("accountService")
public class AccountImpl implements IAccountService {
@Autowired
private IAccountDao dao;
@Override
public List<Account> findAllAccount() {
return dao.findAllAccount();
}
@Override
public Account findById(int id) {
return dao.findById(id);
}
@Override
public void saveAccount(Account account) {
dao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
dao.updateAccount(account);
}
@Override
public void deleteAccount(Account account) {
dao.deleteAccount(account);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void transfer(String source, String target, float money) {
Account Source = dao.findByName(source);
Account Target = dao.findByName(target);
Source.setMoney(Source.getMoney()-money);
Target.setMoney(Target.getMoney()+money);
dao.updateAccount(Source);
dao.updateAccount(Target);
int i = 9/0;//生成异常,看看事务是否是正常运行
}
}
这里是测试之前的数据
aop什么的都正常,也监测出来异常。
数据库的数据没有变,证明事务成功了。