如有错误请指正,谢谢
事物:在一个业务流程中,通常需要多条DML(insert delete update)语句共同联合才能完成的,为了保证数据的安全,多条DML语句都必须同时成功,,或同时失败。
事物的四个处理过程:开启事务、执行核心业务代码、提交事务、回滚事务
事务的四个特性:
原子性:事务是最小工作单位,不可再分割
一致性:事务要么同时成功,要么同时失败,事务前和事务后的总量不变
隔离性:事务和事务之间有隔离性,互不干扰
持久性:持久性是事务结束的标志
Spring实现事务的两种方式
编程式事务:编写代码来实现事务的管理
声明式事务*:基于注解的方式、基于xml配置方式
以银行账户转账为案例
数据库表
spring6整合mybatis
pom.xml配置文件
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.example
spring6-transaction-bank
1.0-SNAPSHOT
17
17
UTF-8
jar
repository.spring.milestone
Spring Milestone Repository
https://repo.spring.io/milestone
jakarta.annotation
jakarta.annotation-api
2.1.0
org.springframework
spring-context
6.0.0-M2
org.springframework
spring-jdbc
6.0.0-M2
mysql
mysql-connector-java
8.0.17
org.mybatis
mybatis
3.5.11
org.mybatis
mybatis-spring
3.0.1
com.alibaba
druid
1.2.15
org.springframework
spring-test
6.0.0-M2
org.springframework
spring-aspects
6.0.0-M2
org.junit.jupiter
junit-jupiter-api
5.8.2
test
src/main/java
**/*.properties
**/*.xml
false
jdbc.properties文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://IP:3306/mysql
jdbc.user= root
jdbc.password= xxxxxx
mybatis-config.xml配置文件
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
SpringConfig.xml配置文件
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
http://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
http://www.springframework.org/schema/aop/spring-aop.xsd
">
BankDao接口
public interface BankDao {
/**
* 根据账号查询账户信息
*/
List selectAll();
/**
* 根据actno查询账户信息
* @param actno
* @return
*/
Bank selectByActno(String actno);
/**
* 更新账户信息
* @param act
* @return
*/
int update(Bank act);
}
BankDao.xml
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
select * from bank
select actno,balance from bank where actno = #{actno}
update bank set balance=#{balance} where actno =#{actno}
pojo实体类
package com.qgs.pojo;
/**
* @author QGS
* @version 1.0.0
* @date 2023年03月24日 16:36:58
* @packageName com.qgs.pojo
* @className Bank
* @describe TODO
*/
public class Bank {
private String actno;
private Double balance;
public Bank() {
}
public Bank(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 "Bank{" +
"actno='" + actno + '\'' +
", balance=" + balance +
'}';
}
}
BankService 接口
public interface BankService {
/**
* 转账方法
* @param fromActno 转出账户
* @param toActno 转入账户
* @param money 金额
*/
void transfer(String fromActno ,String toActno ,double money);
}
BankService 接口实现类
package com.qgs.service;
import com.qgs.dao.BankDao;
import com.qgs.pojo.Bank;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* @author QGS
* @version 1.0.0
* @date 2023年03月25日 11:15:24
* @packageName com.qgs.service
* @className BankServiceImpl
* @describe TODO
*/
@Service("bankServiceImpl")
public class BankServiceImpl implements BankService{
@Resource(name ="bankDao")
private BankDao bankDao;
@Override
public void transfer(String fromActno, String toActno, double money) {
//查询转出账户余额
Bank fromBank = bankDao.selectByActno(fromActno);
if (fromBank.getBalance()
throw new RuntimeException("余额不足");
}
//查询转入账户余额
Bank toBank = bankDao.selectByActno(toActno);
//将内存中转出与转入账户余额修改
fromBank.setBalance(fromBank.getBalance() - money);
toBank.setBalance(toBank.getBalance() + money);
//更新数据库
int count = bankDao.update(fromBank);
int count2 = bankDao.update(toBank);
count +=count2;
if (count !=2){
//回滚事务,转账失败
throw new RuntimeException("失败");
}
}
}
@Test
public void BankTest(){
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("SpringConfig.xml");
BankService bankService = applicationContext.getBean("bankServiceImpl", BankService.class);
try {
bankService.transfer("act01","act2",300);
System.out.println("转账成功");
}catch (Exception e){
e.printStackTrace();
}
}