目录
一、概述
事务定义:
在一组业务逻辑(ABCD)中,要么全部成功,要么全部失败。
事务特性:ACID
- 原子性:事务是一个原子操作单元,其对数据的修改要么全部执行,要么全不执行。
- 一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态。
- 隔离性:多个事务并发执行时,一个事务的执行不应影响其他事务。
- 持久性:一旦事务提交,则其修改的效果就是永久性的。
并发访问问题(隔离问题):
- 脏读:一个事务读到了另一个事务没有提交的数据。
- 不可重复读:一个事务读到了另一个事务已经提交的数据(特质Update)。
- 虚读/幻读:一个事务读到了另一个事务已经提交的数据(特指Insert)。 -- 纯理论
隔离级别: 用于解决隔离问题。
- 读未提交:最低级别的隔离,一个事务可以看到其他还未提交的事务的数据。
- 读已提交:一个事务只能看到已经提交的事务所做的更改。
- 可重复读:保证同一事务中多次读取的数据是一致的。
- 串行化:最高级别的隔离,事务串行执行,可以避免脏读、不可重复读、幻读问题。
常见数据库默认隔离级别:
- mysql:默认基本可重复读。
- oracle:默认基本读已提交:
性能&安全:
- 性能:读未提交> 读已提交> 可重复读 > 串行化
- 安全:读未提交< 读已提交< 可重复读 < 串行化
二、MyBatis事务操作
操作基础代码:
SqlSession sqlSession = null;
try {
//1 开始事务,默认关闭自动提交,言外之意开启事务
// 操作
// 更新语句付款;
// 更新语句收款;
//2 提交事务
sqlSession.commit();
} catch (Exception e) {
//3 回滚事务
sqlSession.rollback();
} finally {
//4 释放资源
sqlSession.close();
}
转账的流程:
创建表:
create table account(
id int primary key auto_increment,
name varchar(10),
money int
);
insert into account(id,name,money) values(null,'jack',100);
insert into account(id,name,money) values(null,'rose',0);
准备工作:
具体操作:
SqlMapConfig.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--在控制台输出发送的sql日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--目前只关注这部分内容,它的作用就是声明要连接的数据信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/day25"/>
<property name="username" value="root"/>
<property name="password" value="25692569"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--声明含有sql的接口所在包-->
<package name="com.czxy.mapper"/>
</mappers>
</configuration>
pom.xml中所需坐标:
<!-- 坐标 -->
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>compile</scope>
</dependency>
</dependencies>
Account类:
package com.czxy.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
private Integer id; // 编号
private String name; // 账户名
private Integer money; // 金额
}
AccountMapper接口:
package com.czxy.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
public interface AccountMapper {
/*
* 收款
* */
@Update("update account set money = money + #{money} where name = #{name}")
public void in(@Param("money") Integer money, @Param("name") String name);
/*
* 汇款
* */
@Update("update account set money = money - #{money} where name = #{name}")
public void out(@Param("money") Integer money, @Param("name") String name);
}
MybatisUtils类:
package com.czxy.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sessionFactory;
static {
try{
// 1. 获取核心文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取会话
sessionFactory = new SqlSessionFactoryBuilder().build(is);
}catch(Exception e) {
throw new RuntimeException(e);
}
}
// 获取session
public static SqlSession getSession() {
SqlSession session = sessionFactory.openSession();
return session;
}
// 释放资源
public static void close(SqlSession session) {
if(session != null) {
// 提交
session.commit();
// 释放
session.close();
}
}
}
TestAccount类:
import com.czxy.mapper.AccountMapper;
import com.czxy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class TestAccount {
@Test
public void testTruncate() {
// 获取session
SqlSession session = MybatisUtils.getSession();
try{
// 通过session获取映射
AccountMapper mapper = session.getMapper(AccountMapper.class);
// 转入
mapper.in(50,"rose");
// 转出
mapper.out(50,"jack");
// 提交事务
session.commit();
System.out.println("转账成功!");
}catch (Exception e) {
// 回退
session.rollback();
System.out.println("转账失败!");
}finally {
// 释放
MybatisUtils.close(session);
}
}
}