事务作用:在数据层保障一系列的数据库操作同成功同失败。
Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败。
举个例子,比如我们要写一个转账的业务,那么这个业务的实现需要两次数据层调用:加钱与减钱。如果把事务放在数据层,那么要有加钱和减钱两个事务。我们没办法保证加钱和减钱同时成功或者同时失败。这个时候就需要将事务放在业务层进行处理。一旦在过程中出现了异常:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void transfer(String out,String in ,Double money) {
accountDao.outMoney(out,money);
int i = 1/0;
accountDao.inMoney(in,money);
}
}
那么转账方减钱了,而收款方却没有收到钱。这一定是不对的。
所以,当程序出问题后,我们需要让事务进行回滚,而且这个事务应该是加在业务层上,而Spring的事务管理就是用来解决这类问题的。
1:在需要被事务管理的方法上添加注解
@Transactional,接口注解/类注解/方法注解,业务层接口上方/业务层实现类上方/业务方法上方,为当前业务层方法添加事务(如果设置在类或接口上方则类或接口中所有方法均添加事务)
public interface AccountService {
/**
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
//配置当前接口方法具有事务
public void transfer(String out,String in ,Double money) ;
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(String out,String in ,Double money) {
accountDao.outMoney(out,money);
int i = 1/0;
accountDao.inMoney(in,money);
}
}
注意:
@Transactional可以写在接口类上、接口方法上、实现类上和实现类方法上。
写在接口类上,该接口的所有实现类的所有方法都会有事务。
写在接口方法上,该接口的所有实现类的该方法都会有事务。
写在实现类上,该类中的所有方法都会有事务。
写在实现类方法上,该方法上有事务。
建议写在实现类或实现类的方法上。
2:在JdbcConfig类中配置事务管理器
public class JdbcConfig {
@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
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
//配置事务管理器,mybatis使用的是jdbc事务
@Bean
public PlatformTransactionManager transactionManager(DataSourcedataSource){
DataSourceTransactionManager transactionManager = new
DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
注意:事务管理器要根据使用技术进行选择,Mybatis框架使用的是JDBC事务,可以直接使用DataSourceTransactionManager
3:开启事务注解
@EnableTransactionManagement,配置类注解,配置类定义上方,设置当前Spring环境中开启注解式事务支持。
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
在未开启事务之前,AccountDao的outMoney因为是修改操作,会开启一个事务T1。AccountDao的inMoney因为是修改操作,会开启一个事务T2。AccountService的transfer没有事务,运行过程中如果没有抛出异常,则T1和T2都正常提交,数据正确;如果在两个方法中间抛出异常,T1因为执行成功提交事务,T2因为抛异常不会被执行,就会导致数据出现错误。
开启Spring的事务管理后,transfer上添加了@Transactional注解,在该方法上就会有一个事务T。AccountDao的outMoney方法的事务T1加入到transfer的事务T中;AccountDao的inMoney方法的事务T2加入到transfer的事务T中。这样就保证他们在同一个事务中,当业务层中出现异常,整个事务就会回滚,保证数据的准确性。