事务
事务是以一种可靠、一致的方式、访问和操作数据库中数据的程序单元。
事务的4大特性ACID
- 原子性
事务中的多个操作要么都完成,要不都不完成,不会只完成其中的一部分 - 一致性
事务执行之后,状态改变是一致的或者说结果是完整的。 - 隔离性
当前事务的操作对于其他事务是否可见 - 持久性
事务提交之后,操作的结果会进入数据库被永久保存。如果事务没有提交,出现数据库宕机,数据不会被保存到数据库中。
eg: 张三给李四转100元钱
原子性:转钱成功后,张三的账户一定是扣掉了100元,李四的账户一定是增加了100元,不会出现单方面账户变化。
一致性:转账成功后,张三的账户扣掉的一定是100元,李四的账户一定是增加了100元,不会出现张三的账户被扣了120元而李四的账户增加了80。
隔离性:张三给李四转账执行的时候的中间状态是否对李四可见,比如张三的账户被扣了100元后,李四的账户还没有加100元这个中间状态是否对李四可见。
持久性:转账成功后(事务提交后)数据被永久存储在数据库中,不会出现数据丢失的情况。
用SQL实现事务
- 创建数据库和表数据
create database test;
use test;
create table t_user(id int PRIMARY key auto_increment,username varchar(32),amount int);
insert t_user(username,amount) values('张三',500),('李四',500);
- 转账事务
START TRANSACTION;
UPDATE t_user SET amount = amount - 100 WHERE username = '张三';
UPDATE t_user SET amount = amount + 100 WHERE username = '李四';
COMMIT;
mysql 的默认隔离级别是可重复读,事务执行的任何中间状态都不会被其他事务看到,也就是说,在转账事务执行的时候,如果另一个事务进行查询操作,查到的账户余额都是事务开始时的余额即,张三,500;李四,500。
使用JDBC实现事务
public class LocalJdbcTransaction {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Connection connection = getConnection();
//关闭自动提交,相当于开启事务
connection.setAutoCommit(false);
String plusSQL = "UPDATE t_user SET amount = amount + 100 WHERE username = ?";
PreparedStatement plusPS = connection.prepareStatement(plusSQL);
plusPS.setString(1, "张三");
plusPS.execute();
String minusSQL = "UPDATE t_user SET amount = amount - 100 WHERE username = ?";
PreparedStatement minusPS = connection.prepareStatement(minusSQL);
minusPS.setString(1, "李四");
minusPS.execute();
plusPS.close();
minusPS.close();
//提交事务
connection.commit();
}
/**
* 获取数据库连接
*
* @return Connection
* @throws SQLException SQLException
* @throws ClassNotFoundException ClassNotFoundException
*/
private static Connection getConnection() throws SQLException, ClassNotFoundException {
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8&autoReconnect=true&serverTimezone=UTC";
String username = "root";
String password = "******";
Class.forName(driver);
return DriverManager.getConnection(url, username, password);
}
}
[具体实现]
public void test() throws SQLException, ClassNotFoundException {
Connection connection = getConnection();
//关闭自动提交,相当于开启事务
connection.setAutoCommit(false);
String selectSQL = "SELECT * from t_user where username = ? for update";
PreparedStatement selectQuery;
selectQuery = connection.prepareStatement(selectSQL);
selectQuery.setString(1,"李四");
ResultSet resultSet = selectQuery.executeQuery();
Long amount = null;
while (resultSet.next()){
String username = resultSet.getString(2);
amount = resultSet.getLong(3);
System.out.println(username+"==>"+amount);
}
String minusSQL = "UPDATE t_user SET amount = ? + 100 WHERE username = ?";
PreparedStatement minusPS = connection.prepareStatement(minusSQL);
minusPS.setLong(1,amount);
minusPS.setString(2, "李四");
minusPS.execute();
minusPS.close();
//提交事务
connection.commit();
}
Spring 事务
Spring事务抽象
-
PlatFormTransactionManager
事务管理器的接口;包括事务开启,提交,回滚等操作
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
-
TransactionDefinition
事务的定义,可以通过该接口定义事务的属性,例如:传播属性,隔离属性
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
@Nullable
String getName();
}
-
TransactionStatus
相当于事务运行过程中的句柄。
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
@Override
void flush();
boolean isCompleted();
}
编程形式使用Spring事务
@Service
public class OrderService {
@Resource
private PlatformTransactionManager txManager;
void buyTicket(){
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// todo 执行业务代码
txManager.commit(status);
}catch (Exception e){
txManager.rollback(status);
}
}
}
声明式事务管理
方法体上加@Transactional