Java事务的类型有三种:
(1)JDBC事务:可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
(2)JTA(Java Transaction API)事务:事务可以跨越多个数据库或多个DAO,使用也比较复杂。
(3)容器事务:主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。
Spring 实现JDBC声明式事务管理可以使用 Annotation 注解。使用注解实现可以减少代码之间的耦合度。
使用 Annotation 的方式非常简单,只需要在项目中做两件事,具体如下。
1)在 Spring 容器中注册驱动,代码如下所示:
或者使用注解
@Aspect
@EnableTransactionManagement //等同于xml配置中的
public class TransactionConfig {}
2)在需要使用事务的业务类或者方法中添加注解 @Transactional,并配置 @Transactional 的参数。关于 @Transactional 的参数如图所示。
常用属性说明如下:
注:以下代码使用springboot
SQL:
INSERT INTO account (username,salary) VALUES ('Bob',3000);
INSERT INTO account (username,salary) VALUES ('Make',3000);
DAO层,在OrdersDao中注入jdbcTemplate,实现数据库操作:
@Repository
public class OrdersDao {
// 注入jdbcTemplate模板对象
@Autowired
private JdbcTemplate springJdbcTemplate;
/**
* Make减去1000
*/
public void reduceMoney() {
String sql = "update account set salary=salary-? where username=?";
springJdbcTemplate.update(sql, 1000, "Make");
}
/**
* Bob增加1000
*/
public void addMoney() {
String sql = "update account set salary=salary+? where username=?";
springJdbcTemplate.update(sql, 1000, "Bob");
}
}
Service层,OrdersService接口
public interface OrdersService {
//转账操作
void accountMoney();
}
具体实现,OrdersServiceImpl
@Service
@Transactional(isolation = Isolation.REPEATABLE_READ,
propagation = Propagation.REQUIRED,
rollbackFor = Exception.class,
readOnly = false)
public class OrdersServiceImpl implements OrdersService{
@Autowired
private OrdersDao ordersDao;
// 调用dao的方法,业务逻辑,写转账业务
public void accountMoney() {
ordersDao.addMoney();
// 2-加入出现异常如下面int
int i=10/0; //银行中可能为突然停电等...
// 3-Make减少1000
ordersDao.reduceMoney();
}
}
application.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springtemplate?useSSL=false
jdbc.username=root
jdbc.password=root
具体配置类,JdbcConfig
@Configuration
public class JdbcConfig {
@Value("${jdbc.driverClass}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/*数据源*/
@Bean("dataSource")
public DriverManagerDataSource getDriverManagerDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(this.driver);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password);
return dataSource;
}
/*jdbc模板*/
@Bean("springJdbcTemplate")
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);//配置数据源
return jdbcTemplate;
}
}
具体配置类,TransactionConfig
@Aspect
@EnableTransactionManagement //等同于xml配置中的
public class TransactionConfig {
/**
* 配置事务管理器 注入连接池
*/
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager(
DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
编写单元测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrdersServiceImplTest {
@Autowired
OrdersService ordersService;
@Test
public void accountMoney() {
ordersService.accountMoney();
}
}
测试结果:
java.lang.ArithmeticException: / by zero
at com.swadian.spring_learn.service.OrdersServiceImpl.accountMoney(OrdersServiceImpl.java:36)
at com.swadian.spring_learn.service.OrdersServiceImpl$$FastClassBySpringCGLIB$$4dccf147.invoke(
因为出现了异常,所以事务实现了回滚,扣款和加钱操作均没有成功(防止了一方加钱成功另一方扣钱失败的情况),保持了数据的一致性。