场景: 从A用户 转帐到B用户并进行日志记录,不管成功失败都进行日志操作,进行事务操作
1、AccountDao接口
@Repository
public interface AccountDao {
@Update("update tbl_account set money = money - #{money} where name = #{name}")
void outMoney(@Param("name") String name, @Param("money") Double money);
@Update("update tbl_account set money = money + #{money} where name = #{name}")
void inMoney(@Param("name") String name, @Param("money") Double money);
}
2、LogDao接口
public interface LogDao {
@Insert("insert into tbl_log(info, createDate) values(#{info}, now())")
void log(@Param("info") String info);
}
3、Account实体类
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString(){
return "Account{" +
"id="+id+
", name='"+name+ '\'' +
", money=" + money+"}";
}
}
4、AccountService接口和实现类
public interface AccountService {
/**
* 转帐操作
* @param out 传入方
* @param in 转入方
* @param money 金额
*/
@Transactional
public void transfer(String out, String in, Double money);
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Autowired
private LogService logService;
public void transfer(String out, String in, Double money) {
try {
accountDao.outMoney(out, money);
// 模拟异常操作
int i = 1 / 0;
accountDao.inMoney(in, money);
} finally {
logService.log(out, in, money);
}
}
}
5、LogService接口和实现类
public interface LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
void log(String out, String in, Double money);
}
@Service
public class LogServiceImpl implements LogService {
@Autowired
private LogDao logDao;
public void log(String out, String in, Double money) {
logDao.log("转帐操作由"+out+"到"+ in +",金额:"+money);
}
}
- @Transactional 设置propagation为Propagation.REQUIRES_NEW 表明这个为新的事务和原来事务不合并
6、测试用例
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer(){
accountService.transfer("Tom", "Jerry", 100D);
}
}
7、补充
7.1、MybatisConfig配置类
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.itheima.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}
7.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;
// step1: 定义一个方法获取要管理的对象
// step2: 添加@Bean 表示当前方法的返回值是一个Bean
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(dataSource);
return tm;
}
}
- 事务管理还需要配置PlatformTransactionManager 管理器才能正常工作
7.3、 SpringConfig配置类
@Configuration
@ComponentScan({"com.itheima"})
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class SpringConfig {
}
- @EnableAspectJAutoProxy 开启AOP切面编程
- @EnableTransactionManagement 开启事务管理
8、使用方法
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = ctx.getBean(AccountService.class);
accountService.transfer("Tom","Jerry", 100D);
}
9、事务传播行为
传播属性 | 事务管理员 | 事务协调员 |
REQUIRED(默认) | 开启T 无 | 加入T 新建T2 |
REQUIRES_NEW | 开启T 无 | 新建T2 新建T2 |
SUPPORTS | 开启T 无 | 加入T 无 |
NOT_SUPPORTED | 开启T 无 | 无 无 |
MANDATORY | 开启T 无 | 加入T ERROR |
NEVER | 开启T 无 | ERROR 无 |
NESTED | 设置savePoint,一旦事务回滚,事务将回滚到saovePoint处,交由客户响应提交/回滚 |