Spring JDBC声明式事务管理

Java事务的类型有三种:

(1)JDBC事务:可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。

(2)JTA(Java Transaction API)事务:事务可以跨越多个数据库或多个DAO,使用也比较复杂。

(3)容器事务:主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。

Spring 实现JDBC声明式事务管理可以使用 Annotation 注解。使用注解实现可以减少代码之间的耦合度。

使用 Annotation 的方式非常简单,只需要在项目中做两件事,具体如下。

1)在 Spring 容器中注册驱动,代码如下所示:

<!-- 注册事务管理驱动 -->
<tx:annotation-driven transaction-manager="transactionManager" />

或者使用注解

@Aspect
@EnableTransactionManagement //等同于xml配置中的 <tx:annotation-driven />
public class TransactionConfig {}

2)在需要使用事务的业务类或者方法中添加注解 @Transactional,并配置 @Transactional 的参数。关于 @Transactional 的参数如图所示。

常用属性说明如下:

  • 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配置中的 <tx:annotation-driven />
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(<generated>)

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值