spring —— 事务管理器

事务管理主要针对数据源进行操作:在数据库方面,通过 TransactionManager 事务管理器进行管理,表明一旦出现错误,该数据源的所有数据全部复原。那么数据库如何判断是否发生了错误呢?这就需要在代码方面,通过 @Transactional 注解管理相应的方法,表示一旦该方法出现错误,那么由该方法调用的数据就要执行回滚。

一、spring-config.xml 文件配置

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.spring.book"></context:component-scan>
    <!--引入外部文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--使用druid工具配置数据源-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--将数据源作为属性传入JDBCTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>
    <!--将数据源作为属性传入DataSourceTransactionManager事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>
    <!--启用事务管理器注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

二、数据库

balance 设置为"无符号",也就是不能为负数。

三、java 代码

Dao 层类:

java 复制代码
package com.spring.book;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Integer getPriceByBookId(Integer bookId){
        String sql = "select price from book where bookid=?";
        return jdbcTemplate.queryForObject(sql, Integer.class, bookId);
    }

    public void updateStock(Integer bookId){
        String sql = "update book set stock=stock-1 where bookid=?";
        jdbcTemplate.update(sql, bookId);
    }

    public void updateBalance(Integer userId, Integer price){
        String sql = "update user set balance=balance-? where userid=?";
        jdbcTemplate.update(sql, price, userId);
    }
}

Service 类:

java 复制代码
package com.spring.book;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void buyBook(Integer bookId, Integer userId){
        Integer price=bookDao.getPriceByBookId(bookId);
        bookDao.updateStock(bookId);
        bookDao.updateBalance(userId,price);
    }
}

Controller 类:

java 复制代码
package com.spring.book;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class BookController {
    @Autowired
    private BookService bookService;

    public void buyBook(Integer bookId, Integer userId){
        bookService.buyBook(bookId,userId);
    }
}

测试类:

java 复制代码
import com.spring.book.BookController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.transaction.annotation.Transactional;

@SpringJUnitConfig(locations = "classpath:bean-jdbc.xml")
public class TxByAnnotationTest {
    @Autowired
    private BookController bookController;
    @Test
    @Transactional
    public void testBuyBook(){
        bookController.buyBook(1,1);
    }
}

四、说明

该案例模拟 user 从 book 列表中买书的过程,如果交易成功,book 的库存减少 1,user 的资金减少相应的价格。如果不添加事务管理的话,Dao 层的各个方法是互不影响的,会出现资金不减少,但库存减少的情况,因此需要将这些方法作为一个统一的整体。此时可以将 @Transactional 注解添加在 Service 层、Controller 层或者 Test 层均可实现效果,也就是说受到 @Transactional 注解影响到的方法一旦出现错误,那么该方法调用的数据都将恢复原状。而究竟是哪些数据,则由 spring-config.xml 配置文件的 TransactionManager 确定。

相关推荐
踏月的造梦星球3 小时前
DMDPC 学习:架构、部署、运维与调优
运维·数据库·学习·架构
韩楚风3 小时前
【参天引擎】事务生命周期 / MVCC / Undo / ACID / 分布式事务 功能域整体解析
数据库·分布式·mysql·架构·cantian
阿维的博客日记4 小时前
MultipartFile 是不是表示仅仅是一个分片?
java·后端·spring·multipartfile
renhongxia14 小时前
世界模型,是“空中楼阁”还是AGI的“最后一块拼图”?
运维·服务器·数据库·人工智能·算法·agi
程序员无隅4 小时前
Coding Agent 为什么压缩上下文后还能继续工作?上下文模块设计拆解
java·开发语言·数据库
愿做无知一猿5 小时前
Nacos连接MySQL异常?DataGrip竟成救星
数据库·mysql
G.O.G.O.G5 小时前
LeetCode SQL 从入门到精通(MySQL)06(上)
数据库·sql·mysql·leetcode
一路向北North5 小时前
Spring Security OAuth2.0(23):分布式系统授权-转发明文给微服务
java·spring·微服务
研究员子楚5 小时前
GEO行业发展标准体系白皮书V2.0-第10卷 · 全球篇:跨国标准协同与全球品牌语义治理框架
数据库·人工智能·microsoft·架构·geo
Omics Pro6 小时前
深度学习多组学互作:组内+组间
数据库·人工智能·深度学习·mysql·搜索引擎·自然语言处理