Spring JDBC声明式事务管理

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 的参数如图所示。

Spring JDBC声明式事务管理_第1张图片

常用属性说明如下:

  • propagation:设置事务的传播行为
  • isolation:设置事务的隔离级别
  • readOnly:设置是读写事务还是只读事务
  • timeout:事务超时事件(单位:s)

示例代码如下:

注:以下代码使用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()

因为出现了异常,所以事务实现了回滚,扣款和加钱操作均没有成功(防止了一方加钱成功另一方扣钱失败的情况),保持了数据的一致性。

你可能感兴趣的:(Spring,spring,java,数据库,声明式事务,JDBC事务)