事务是数据库操作最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败所有操作都失败。
原子性:不可分割,要么成功,要么都失败。
一致性:操作之前和操作之后的总量是不变得。
隔离性:多事务间不影响。
持久性:事务提交后,表中数据发生持久变化。
典型场景:银行转账
场景描述:小明去银行转账给小红100元,小明执行转账方法,方法执行后,小明的账户减少100元,小红的账户增加100元。
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account` (
`id` int(11) NOT NULL,
`user_name` varchar(55) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
`money` decimal(11, 2) NULL DEFAULT NULL COMMENT '账户金额',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account` VALUES (1, '小明', 1000.00);
INSERT INTO `t_account` VALUES (2, '小红', 1000.00);
SET FOREIGN_KEY_CHECKS = 1;
package org.learn.spring5.service;
public interface UserService {
public void transferAccount();
}
package org.learn.spring5.service.impl;
import org.learn.spring5.dao.UserDao;
import org.learn.spring5.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public void transferAccount() {
//小明转账100,减少100元
userDao.reduceMoney();
//小红账户增加100元
userDao.addMoney();
}
}
package org.learn.spring5.dao.impl;
import org.learn.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int reduceMoney() {
String sql=" update t_account set money=money-100 where user_name ='小明'";
Object[] args = {};
int update = jdbcTemplate.update(sql, args);
return update;
}
public int addMoney() {
String sql=" update t_account set money=money+100 where user_name ='小红'";
Object[] args = {};
int update = jdbcTemplate.update(sql, args);
return update;
}
}
package org.learn.spring5.dao;
public interface UserDao {
//账户金额减少的方法
public int reduceMoney();
//账户金额增加的方法
public int addMoney();
}
package org.learn.spring5.dao.impl;
import org.learn.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int reduceMoney() {
String sql=" update t_account set money=money-100 where user_name ='小明'";
Object[] args = {};
int update = jdbcTemplate.update(sql, args);
return update;
}
public int addMoney() {
String sql=" update t_account set money=money+100 where user_name ='小红'";
Object[] args = {};
int update = jdbcTemplate.update(sql, args);
return update;
}
}
从上面代码我们可以分析出,Service层用于处理业务,具体有两部操作,小明转账,账户减少100元,和小红账户增加100元
Dao层用于操作数据库,分别执行了小明账户减少100和小红账户增加100的数据操作,如果我们没有使用事务发生异常会发生什么问题呢?
假如在处理如上业务逻辑时1.小明转账,账户减少100,当执行完这步操作时,网络突然中断,没有执行下一步操作,这时候数据库会执
行小明账户减少100元的操作,结果是小明的账户减少100,而小红的账户金额没有发生变化。这种情况明显是错误的。正常情况应该是如果转账成功,小明账户减少100,小红账户增加100。如果发生异常,小明和小红的账户金额应该保持不变。如何处理这个问题呢?事务的引入就可以解决这个问题,让我们在回顾一下事务的定义:逻辑上的一组操作,要么都成功,如果有一个失败所有操作都失败。
增加事务的步骤
在要增加事务的方法内添加如下的代码流程
1、开启事务
2、进行业务操作
3、如果没有发生异常,事务提交
4、如果在处理业务逻辑时出现异常,事务回滚
@Autowired
private UserDao userDao;
public void transferAccount() {
try{
//1.开启事务
//2.业务逻辑的处理
//小明转账100,减少100元
userDao.reduceMoney();
//小红账户增加100元
userDao.addMoney();
}catch(Exception e){
//3.如果存在异常,事务回滚
}
//4.事务提交
}
思考一个问题,如果系统中存在很多功能,每个功能的业务逻辑处理的Service类都需要增加事务代码的编写,会发生什么问题?
第一,代码会变得非常臃肿,冗余。
第二,业务方法功能变得复杂而不清晰。
然而,Spring集成了对事务的管理,恰恰解决了这些问题,大大减少了程序员的代码量,也对事务有了很好的管理控制。业务层只需要专心业务的处理。
本章节主要对事务进行了一个介绍,如何用Spring实现事务管理我们将会下个章节介绍。