一、概述
什么是事务?
在一个业务流程当中,通常需要多条DML(insert,delete,update)语句同共完成,这多条DML语句须要同时成功或者同时失败,这样才能保证数据安全。
多条DML要么同时成功,要么同时失败,这叫做事务。
事务处理的四个过程:
第一步:开始事务
第二步:执行业务代码
第三步:如果业务代码未出现异常,则提交事务
第四步:如果业务代码出现异常,则回滚事务
事务的四个特特征:
原子性(A):事务是最小的工作单元,不可再分
一致性(C):事务要么同时成功,要么同时失败
隔离性(I):事务与事务这间是相互隔离的,不可以相互干扰
持久性(D):持久性是事务结束的标志
接下来我们以简单的示例来说明事务的处理,比如,我们有两个账户:act-001,act-002,它们之间相互进行转账操作,必须要保证一方的账户的扣减与和另一方账户的增加同时成功或同时失败。
示例中数据表结构如下:
CREATE TABLE `t_act` (
`id` bigint NOT NULL AUTO_INCREMENT,
`actno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '',
`balance` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
我们新建工程,添加如下依赖
<dependencies>
<!-- spring context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.9</version>
</dependency>
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.1.9</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.13</version>
</dependency>
<!-- @Resource -->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
新增jdbc的配置文件:jdbc.properties
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
准备与数据库表相对应的实体类:Account
public class Account {
private String actno;
private String balance;
public Account() {
}
public Account(String actno, String balance) {
this.actno = actno;
this.balance = balance;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"actno='" + actno + '\'' +
", balance='" + balance + '\'' +
'}';
}
}
编写Dao接口:AccountDao
public interface AccountDao {
/**
* 根据账号查询账户信息
* @param actno
* @return
*/
Account selectByActno(String actno);
/**
* 更新账户信息
* @param act
* @return
*/
int update(Account act);
}
编写Dao实现:AccountDaoImpl
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Resource(name = "jdbcTemplate")
private JdbcTempla