声明式事务(Declarative Transaction Management)是Spring框架提供的一种对程序事务进行管理的方式。这种管理方式的核心思想是采用声明的方式(通常是在配置文件中声明,而非在代码中硬编码)来处理事务,从而简化开发过程,降低开发者处理复杂事务的难度。
在声明式事务中,开发者通过注解(如@Transactional)或基于配置的XML来管理事务,而不需要依赖底层API进行硬编码。这使得业务逻辑对象无需意识到它们正处于事务管理之中,因为事务管理属于系统层面的服务,而不是业务逻辑的一部分。因此,当需要改变事务管理策略时,只需在配置文件中重新配置即可,无需修改代码并重新编译,从而大大提高了维护的便利性。
转账案例
| package com.powernode.bank.dao; |
| |
| |
| import com.powernode.bank.pojo.Account; |
| |
| public interface AccountDao { |
| |
| Account selectByActno(String actno); |
| |
| |
| int update(Account act); |
| |
| |
| int insert(Account act); |
| } |
| package com.powernode.bank.dao.impl; |
| |
| import com.powernode.bank.dao.AccountDao; |
| import com.powernode.bank.pojo.Account; |
| import jakarta.annotation.Resource; |
| import org.springframework.jdbc.core.BeanPropertyRowMapper; |
| import org.springframework.jdbc.core.JdbcTemplate; |
| import org.springframework.stereotype.Repository; |
| |
| @Repository |
| public class AccountDaoImpl implements AccountDao { |
| |
| @Resource |
| private JdbcTemplate jdbcTemplate; |
| |
| |
| @Override |
| public Account selectByActno(String actno) { |
| String sql = "select actno,balance from t_act where actno = ?"; |
| Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno); |
| System.out.println("笑"+account); |
| return account; |
| } |
| |
| @Override |
| public int update(Account act) { |
| String sql = "update t_act set balance = ? where actno = ?"; |
| int update = jdbcTemplate.update(sql, act.getBalance(), act.getActno()); |
| return update; |
| } |
| |
| @Override |
| public int insert(Account act) { |
| String sql = "insert into t_act values(?,?)"; |
| return jdbcTemplate.update(sql,act.getActno(),act.getBalance()); |
| } |
| } |
| package com.powernode.bank.pojo; |
| |
| public class Account { |
| private String actno; |
| private Double balance; |
| |
| public Account() { |
| } |
| |
| public Account(String actno, Double balance) { |
| this.actno = actno; |
| this.balance = balance; |
| } |
| |
| public String getActno() { |
| return actno; |
| } |
| |
| public void setActno(String actno) { |
| this.actno = actno; |
| } |
| |
| public Double getBalance() { |
| return balance; |
| } |
| |
| public void setBalance(Double balance) { |
| this.balance = balance; |
| } |
| |
| @Override |
| public String toString() { |
| return "Account{" + |
| "actno='" + actno + '\'' + |
| ", balance=" + balance + |
| '}'; |
| } |
| } |
| package com.powernode.bank.service; |
| |
| public interface AccountService { |
| void transfer(String fromActno, String toActno, double money); |
| } |
| package com.powernode.bank.service.impl; |
| |
| import com.powernode.bank.dao.AccountDao; |
| import com.powernode.bank.pojo.Account; |
| import com.powernode.bank.service.AccountService; |
| import jakarta.annotation.Resource; |
| import org.springframework.stereotype.Service; |
| import org.springframework.transaction.annotation.Transactional; |
| |
| @Service |
| public class AccountServiceImpl implements AccountService { |
| @Resource |
| private AccountDao accountDao; |
| |
| |
| @Override |
| public void transfer(String fromActno, String toActno, double money) { |
| |
| Account fromAct = accountDao.selectByActno(fromActno); |
| if (fromAct.getBalance() < money){ |
| throw new RuntimeException("余额不足!!"); |
| } |
| |
| Account toAct = accountDao.selectByActno(toActno); |
| |
| |
| fromAct.setBalance(fromAct.getBalance() - money); |
| toAct.setBalance(toAct.getBalance() + money); |
| |
| |
| int count = accountDao.update(fromAct); |
| |
| |
| |
| |
| |
| count += accountDao.update(toAct); |
| |
| |
| |
| if (count !=2){ |
| throw new RuntimeException("转账失败,联系银行"); |
| } |
| } |
| |
| } |
| <?xml version="1.0" encoding="UTF-8"?> |
| <beans xmlns="http://www.springframework.org/schema/beans" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" |
| xmlns:aop="http://www.springframework.org/schema/aop" |
| xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
| http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd |
| http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd |
| http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> |
| |
| |
| <context:component-scan base-package="com.powernode.bank"/> |
| |
| |
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> |
| <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> |
| <property name="url" value="jdbc:mysql://192.168.1.41:3306/test"/> |
| <property name="username" value="root"/> |
| <property name="password" value="Abc123***"/> |
| </bean> |
| |
| |
| <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> |
| <property name="dataSource" ref="dataSource"/> |
| </bean> |
| |
| |
| <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> |
| <property name="dataSource" ref="dataSource"/> |
| </bean> |
| |
| |
| |
| |
| |
| <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager"> |
| |
| <tx:attributes> |
| <tx:method name="transfer" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> |
| </tx:attributes> |
| </tx:advice> |
| |
| |
| <aop:config> |
| |
| <aop:pointcut id="txPointcut" expression="execution(* com.powernode.bank.service..*(..))"/> |
| |
| <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> |
| </aop:config> |
| |
| </beans> |
| @Test |
| public void testNoAnnotation() { |
| ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml"); |
| AccountService accountServiceImpl = classPathXmlApplicationContext.getBean("accountServiceImpl", AccountService.class); |
| try { |
| accountServiceImpl.transfer("act-001", "act-002", 10000); |
| System.out.println("转账成功"); |
| } catch (Exception e){ |
| e.printStackTrace(); |
| } |
| } |
数据库截图

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)