JDBC
JDBC
1 JDBC介绍
JDBC: java database connectivity
"编写java程序,实现任意一个DBMS软件的数据进行增删改查,都需要使用JDBC"
JDBC是sun公司发布的一套关于数据库的规范
JDBC实际是一套接口,各个数据库厂商都需要实现这个接口。实现接口中的方法。
好处:程序员只需要学会JDBC接口,就可以调用各个数据库厂商的内容,轻松实现增删改查
各个数据库厂商需要提供JDBC接口的实现,这些实现称之为驱动。
2 获取DBMS连接
获取特定的DBMS的连接
-- 1.用户名
-- 2.密码
-- 3.数据库的ip和端口号和数据库名称
-- 4.mysql驱动
2.1 获取连接
- 导入jar包,并且添加到类路径下

- 编写代码
public static void main(String[] args) {
// 用户名
String username = "root";
// 密码
String password = "root";
// 数据库的ip和端口号和数据库名称
String url = "jdbc:mysql://localhost:3306/mydb";
Connection connection = null;
try {
// 注册驱动
DriverManager.registerDriver(new Driver());
// 获取连接
connection = DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
if (connection != null){
// 关闭连接
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
System.out.println(connection);
}
2.2 注册驱动代码优化
在Driver类中的静态代码块中已经注册过驱动

我们只需要让类加载到内存中,就会自动调用静态代码块去注册驱动

2.3 工具类封装获取连接
在src目录下创建jdbc.properties文件
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql:///mydb
jdbc.driver=com.mysql.cj.jdbc.Driver
编写代码
package cn.javas.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* @className: DBUtil
* @description:
* @author: gfs
* @date: 2025/7/21 14:50
* @version: 0.1
* @since: jdk17
*/
public class DBUtil {
private static Properties properties = new Properties();
private DBUtil(){}
static {
try {
// 读取文件 在静态代码块中只会读取一次
properties.load(new FileInputStream("src\\jdbc.properties"));
// 注册驱动
Class.forName(properties.getProperty("jdbc.driver"));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 获取连接
*/
public static Connection getConnection(){
Connection connection = null;
try {
connection = DriverManager.getConnection(properties.getProperty("jdbc.url"), properties.getProperty("jdbc.username"), properties.getProperty("jdbc.password"));
} catch (SQLException e) {
throw new RuntimeException(e);
}
return connection;
}
/**
* 关闭连接
*/
public static void release(Connection connection){
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
3 CRUD
3.1 添加 insert
/**
* 添加用户
* @return 影响数据库的行数
*/
int addUser();
@Override
public int addUser() {
// 1. 获取数据库连接
Connection connection = DBUtil.getConnection();
// 2. 编写sql语句
String sql = "insert into user (username,age,password,balance) values('张翠山',20,'345',2000.1)";
int row = 0;
PreparedStatement preparedStatement = null;
try {
// 3. 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 4. 指定sql语句,获取返回结果 -- 数据库受影响的行数
row = preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 5. 释放资源
DBUtil.release(connection,preparedStatement);
}
return row;
}
优化代码
上面的代码每次添加的都是一个人,没有实际意义
- 定义实体类
package cn.javasm.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* @className: User
* @description:
* @author: gfs
* @date: 2025/7/21 15:16
* @version: 0.1
* @since: jdk17
*/
@Data
@Accessors(chain = true)
public class User {
/**
* 用户id
*/
private Long id;
/**
* 用户名
*/
private String username;
/**
* 年龄
*/
private Integer age;
/**
* 密码
*/
private String password;
/**
* 头像
*/
private String image;
/**
* 存款
*/
private BigDecimal balance;
/**
* 注册时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
- UserDao接口中
/**
* 添加用户
* @param user 添加的用户对象
* @return 影响数据库的行数
*/
int addUser(User user);
- UserDao实现类中
@Override
public int addUser(User user) {
// 获取数据库连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
// ? 代表占位符, 在jdbc中一个?占一个位置,代表一个数据
String sql = "insert into user (username,age,password) values(?,?,?)";
PreparedStatement preparedStatement = null;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setString(1, user.getUsername());
preparedStatement.setInt(2,user.getAge());
preparedStatement.setObject(3,user.getPassword());
// 执行sql语句,获取结果
int row = preparedStatement.executeUpdate();
return row;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放连接
DBUtil.release(connection,preparedStatement);
}
}
3.2 删除 delete
- UserDao接口中
/**
* 根据id删除用户
* @param id 用户的id
* @return 影响数据库的行数
*/
int deleteUserById(Long id);
- UserDapImpl类中
@Override
public int deleteUserById(Long id) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "delete from user where id = ?";
PreparedStatement preparedStatement = null;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setLong(1,id);
// 执行sql语句,返回结果
return preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement);
}
}
3.3 更新 update
update user set username = ?,age = ?,password = ? ,image = ? where id = ?
- UserDao接口中
/**
* 更新用户
* @param user 用户信息
* @return 影响数据库的行数
*/
int updateUserById(User user);
- UserDaoImpl实现类中
@Override
public int updateUserById(User user) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "update user set username = ?,age = ?,password = ? ,image = ? where id = ?";
PreparedStatement preparedStatement = null;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setString(1,user.getUsername());
preparedStatement.setInt(2,user.getAge());
preparedStatement.setString(3,user.getPassword());
preparedStatement.setString(4,user.getImage());
preparedStatement.setLong(5,user.getId());
// 执行sql语句,返回结果
return preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement);
}
}
3.4 查询 select
3.4.1 根据id查询
- UserDao接口中
/**
* 根据id查询用户
* @param id 用户的id
* @return 查询的用户
*/
User queryUserById(Long id);
- UserDaoImpl实现类中
@Override
public User queryUserById(Long id) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql
String sql = "select * from user where id = ?";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setLong(1,id);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
// next() 返回true代表有下一个记录
if (resultSet.next()){
// 获取记录的数据
// 根据表中的字段位置获取
long uid = resultSet.getLong(1);
// 根据表中的字段名称获取
String username = resultSet.getString("username");
int age = resultSet.getInt(3);
String password = resultSet.getString(4);
String image = resultSet.getString("image");
BigDecimal balance = resultSet.getBigDecimal(6);
LocalDateTime createTime = (LocalDateTime) resultSet.getObject(7);
LocalDateTime updateTime = (LocalDateTime) resultSet.getObject(8);
// 把查询出来的结果封装成一个对象并返回
User user = new User().setImage(image).setId(uid).setUsername(username).setAge(age).setPassword(password).setBalance(balance).setCreateTime(createTime).setUpdateTime(updateTime);
return user;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
DBUtil.release(connection,preparedStatement,resultSet);
}
return null;
}
3.4.2 查询所有
- UserDao接口中
/**
* 查询所有
* @return 所有的用户
*/
List<User> queryAll();
- UserDaoImpl实现类中
@Override
public List<User> queryAll() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select * from user";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// 创建集合
List<User> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
// 获取数据,封装对象
list.add(getUser(resultSet));
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
DBUtil.release(connection,preparedStatement,resultSet);
}
}
3.4.3 分页查询
后端需要知道当前请求的是哪一页,每一页显示几条数据
前端需要知道当前页的数据以及页面的总数量
select * from user limit ?,?
第一个?: (page - 1) * pageSize
第二个?: pageSize
select count(*) from user;
- UserDao接口中
/**
* 查询数据的总数量
* @return 数据的总数量
*/
int queryUserCount();
/**
* 分页查询
* @param page 第几页
* @param pageSize 一页显示多少
* @return 分页查询后的数据
*/
List<User> queryUserByPage(int page,int pageSize);
- UserDaoImpl中
@Override
public List<User> queryUserByPage(int page, int pageSize) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select * from user limit ?,?";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<User> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setInt(1,(page - 1) * pageSize);
preparedStatement.setInt(2,pageSize);
// 执行sql语句,返回结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
list.add(getUser(resultSet));
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
}
3.4.4 多表查询
-- 查询用户的id,用户名,用户年龄,用户角色,用户的部门
SELECT
u.id,u.username,u.age,r.role_name,d.dname
from
user u,role r,mydb2.dept d
where
u.rid = r.id
AND
u.deptno = d.deptno
实现方式一:
- 定义结果类
@Data
@Accessors(chain = true)
public class UserRoleDeptVo {
/**
* 用户id
*/
private Long id;
/**
* 用户名
*/
private String username;
/**
* 用户年龄
*/
private Integer age;
/**
* 角色名称
*/
private String roleName;
/**
* 部门名称
*/
private String dname;
}
- UserDao接口中添加抽象方法
/**
* 查询用户角色和部门
* @return 查询结果
*/
List<UserRoleDeptVo> queryUserAndRoleAndDept();
- UserDaoImpl实现类中
@Override
public List<UserRoleDeptVo> queryUserAndRoleAndDept() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "SELECT\n" +
"u.id,u.username,u.age,r.role_name,d.dname\n" +
"from \n" +
"user u,role r,mydb2.dept d\n" +
"where \n" +
"u.rid = r.id\n" +
"AND\n" +
"u.deptno = d.deptno";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<UserRoleDeptVo> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
// 获取数据
long uid = resultSet.getLong(1);
String username = resultSet.getString(2);
int age = resultSet.getInt(3);
String roleName = resultSet.getString(4);
String dname = resultSet.getString(5);
// 创建对象并赋值
UserRoleDeptVo userRoleDeptVo = new UserRoleDeptVo().setId(uid).setUsername(username).setAge(age).setRoleName(roleName).setDname(dname);
list.add(userRoleDeptVo);
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
}
实现方式二
- 定义 Role类
@Data
@Accessors(chain = true)
public class Role {
/**
* 用户id
*/
private Long id;
/**
* 角色名称
*/
private String roleName;
/**
* 角色描述
*/
private String roleDesc;
}
- 定义Dept类
@Data
@Accessors(chain = true)
public class Dept {
/**
* 部门id
*/
private Integer deptno;
/**
* 部门名称
*/
private String dname;
/**
* 部门位置
*/
private String loc;
}
- 定义UserRoleDept类
@Data
@Accessors(chain = true)
public class UserRoleDept {
/**
* 用户
*/
private User user;
/**
* 角色
*/
private Role role;
/**
* 部门
*/
private Dept dept;
}
- UserDao接口中
/**
* 查询用户角色部门信息
*/
List<UserRoleDept> findUserAndRoleAndDept();
- UserDaoImpl类中
@Override
public List<UserRoleDept> findUserAndRoleAndDept() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "SELECT\n" +
"u.*,r.*,d.*\n" +
"from \n" +
"user u,role r,mydb2.dept d\n" +
"where \n" +
"u.rid = r.id\n" +
"AND\n" +
"u.deptno = d.deptno";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<UserRoleDept> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql语句
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
User user = getUser(resultSet);
long rid = resultSet.getLong(11);
String roleName = resultSet.getString(12);
String roleDesc = resultSet.getString(13);
int deptno = resultSet.getInt(14);
String dname = resultSet.getString(15);
String loc = resultSet.getString("loc");
Role role = new Role().setId(rid).setRoleName(roleName).setRoleDesc(roleDesc);
Dept dept = new Dept().setDeptno(deptno).setDname(dname).setLoc(loc);
UserRoleDept userRoleDept = new UserRoleDept().setUser(user).setRole(role).setDept(dept);
list.add(userRoleDept);
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
}
3.4.5 根据条件查询并分页
-- 条件
1 根据用户名模糊查询
2 根据年龄在区间范围内查询 minAge maxAge
3 create_time区间范围内查询 beginTime endTime
-- 没有条件
select * from user limit ?,?
-- 用户名
select * from user where username like ? limit ?,?
-- 用户名 年龄
select * from user where username like ? AND age between ? AND ? limit ?,?
-- 用户名 年龄 时间
select * from user where username like ? AND age between ? AND ? AND create_time between ? AND ? limit ?,?
-- 没有条件
select count(*) from user;
-- 用户名
select count(*) from user where username like ?;
-- 用户名年龄
select count(*) from user where username like ? AND age between ? AND ?
-- 动态拼接sql
where username like ? AND age between ? AND ? AND create_time between ? AND ?
- UserDao接口中
/**
* 按照条件分页查询
* @param searchParamVo 查询条件
* @param page 第几页
* @param pageSize 每页显示的数量
* @return 结果
*/
List<User> queryUserByParamAndPage(SearchParamVo searchParamVo,int page,int pageSize);
/**
* 按照条件查询总数量
* @param searchParamVo 条件
* @return 总数量
*/
int queryUserByParamCount(SearchParamVo searchParamVo);
- UserDaoImpl实现类中
package cn.javasm.dao.impl;
import cn.javasm.dao.UserDao;
import cn.javasm.entity.User;
import cn.javasm.utils.DBUtil;
import cn.javasm.vo.SearchParamVo;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* @className: UserDaoImpl
* @description:
* @author: gfs
* @date: 2025/7/22 10:07
* @version: 0.1
* @since: jdk17
*/
public class UserDaoImpl implements UserDao {
@Override
public List<User> queryUserByParamAndPage(SearchParamVo searchParamVo, int page, int pageSize) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 拼接sql语句
StringBuilder stringBuilder = new StringBuilder();
// 拼接sql语句前面固定的内容
stringBuilder.append("select * from user ");
// 动态拼接sql
appendSql(searchParamVo,stringBuilder);
stringBuilder.append(" limit ?,?");
System.out.println(stringBuilder);
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<User> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(stringBuilder.toString());
int count = setParamterValue(searchParamVo, preparedStatement);
// 给limit?赋值
preparedStatement.setInt(count++,(page - 1) * pageSize);
preparedStatement.setInt(count,pageSize);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
list.add(getUser(resultSet));
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
}
private int setParamterValue(SearchParamVo searchParamVo,PreparedStatement preparedStatement) throws SQLException {
String nameParam = searchParamVo.getNameParam();
Integer minAge = searchParamVo.getMinAge();
Integer maxAge = searchParamVo.getMaxAge();
String beginTime = searchParamVo.getBeginTime();
String endTime = searchParamVo.getEndTime();
// 记录参数的位置
int count = 1;
// 给?赋值
if (nameParam != null && !nameParam.isBlank()){
preparedStatement.setString(count++,"%" + nameParam + "%");
}
if (minAge != null){
preparedStatement.setInt(count++,minAge);
preparedStatement.setInt(count++,maxAge);
}
if (beginTime != null && !beginTime.isBlank()){
preparedStatement.setString(count++,beginTime);
preparedStatement.setString(count++,endTime);
}
return count;
}
private void appendSql(SearchParamVo searchParamVo,StringBuilder stringBuilder){
// 获取搜索条件
String nameParam = searchParamVo.getNameParam();
Integer minAge = searchParamVo.getMinAge();
String beginTime = searchParamVo.getBeginTime();
// 判断是否已经添加过where true代表添加过
boolean flag = false;
if (nameParam != null && !nameParam.isBlank()){
stringBuilder.append(" WHERE ");
stringBuilder.append(" username like ? AND");
flag = true;
}
if (minAge != null){
if (!flag){
stringBuilder.append(" WHERE ");
flag = true;
}
stringBuilder.append(" age between ? AND ? AND");
}
if (beginTime != null && !beginTime.isBlank()){
if (!flag){
stringBuilder.append(" WHERE ");
flag = true;
}
stringBuilder.append(" create_time between ? AND ? AND");
}
if (flag){
// 删除最后多余的一个AND
stringBuilder.delete(stringBuilder.lastIndexOf("AND"),stringBuilder.length());
}
}
private static User getUser(ResultSet resultSet) throws SQLException {
// 根据表中的字段位置获取
long uid = resultSet.getLong(1);
// 根据表中的字段名称获取
String username = resultSet.getString("username");
int age = resultSet.getInt(3);
String password = resultSet.getString(4);
String image = resultSet.getString("image");
BigDecimal balance = resultSet.getBigDecimal(6);
LocalDateTime createTime = (LocalDateTime) resultSet.getObject(7);
LocalDateTime updateTime = (LocalDateTime) resultSet.getObject(8);
// 把查询出来的结果封装成一个对象并返回
User user = new User().setImage(image).setId(uid).setUsername(username).setAge(age).setPassword(password).setBalance(balance).setCreateTime(createTime).setUpdateTime(updateTime);
return user;
}
@Override
public int queryUserByParamCount(SearchParamVo searchParamVo) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 拼接sql
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select count(*) from user ");
appendSql(searchParamVo,stringBuilder);
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(stringBuilder.toString());
// 给?赋值
setParamterValue(searchParamVo,preparedStatement);
// 执行sql,获取结果集
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
int count = resultSet.getInt(1);
return count;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return 0;
}
}
3.5 新增角色
-- 展示所有的权限菜单
select * from menu;
-- 在角色表中新增一条记录
insert into role (role_name,role_desc) values(?,?)
-- 在中间表中添加角色和菜单的关系
insert into role_menu(rid,mid) values(?,?),(?,?)...
4 DCL(事务)
事务是逻辑上的一组操作,组成这组操作的单元要么同时成功,要么同时失败
准备工作:
create table account(
id int PRIMARY KEY auto_increment,
name varchar(200),
money double
);
insert into account values(null,'zs',1000),(null,'ls',1000),(null,'ww',1000);
4.1 Mysql进行事务管理
- 手动开启事务
start transaction; 开启事务
commit; 提交事务
rollback; 回滚事务
start transaction; -- 开启事务
update account set money = money - 100 where name = 'zs';
update account set money = money + 100 where name = 'ls';
commit;-- 提交事务
rollback;-- 回滚事务
4.2 事务的特性和隔离级别【面试题】
4.2.1 事务的特性
- 原子性:原子性是指事物是一个不可分割的工作单位,事务中的操作要么都成功,要么都失败
eg: zs 1000 ls 1000
zs给ls转100
要么都成功 zs 900 ls 1100
要么都失败 zs 1000 ls 1000
- 一致性:事务前后数据的完整性要保持一致
eg:
zs 1000 ls 1000 总共2000
成功 zs 900 ls 1100 总共2000
失败 zs 1000 ls 1000 总共2000
- 持久性:指一个事务一旦被提交,它对数据库中的数据改动是永久性的。
- 隔离性:事务的隔离性是指多个用户并发操作数据库时,一个用户的事务不能被其他用户的事务所影响。多个并发事务之间的数据要相互隔离。简单来说,事务之间互不干扰。
4.2.2 没有隔离性会引发问题
| 可能出现的问题 | 含义 |
|---|---|
| 脏读 | 一个事务读取到了另一个事务尚未提交的数据 |
| 不可重复读 | 一个事务中两次读取到的数据内容不一致,这是事务update引起的 |
| 幻读 | 一个事务中两次读取到的数据的数量不一致,这是insert或者delete引起的 |
4.2.3 事务的隔离级别
| 级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认级别 |
|---|---|---|---|---|---|---|
| 1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
| 2 | 读已提交 | read committed | 否 | 是 | 是 | oracle |
| 3 | 可重复读 | repeatable read | 否 | 否 | 是 | mysql |
| 4 | 串行化 | serializable | 否 | 否 | 否 |
隔离级别越高,安全性越高,性能效率越差
查看当前的隔离级别
select @@transaction_isolation;
临时设置数据库的隔离级别
set session transaction isolation level 隔离级别
4.2.4 演示脏读
一个事务中读取到了另一个事务没有提交的数据 read uncommitted;
1 开启AB窗口
2 设置A窗口的隔离级别是 读未提交
set session transaction isolation level read uncommitted
3 AB窗口中都开启事务
4 在B中把zs的金额减少100,不要提交事务
5 在A中查询,发现账户内容出现了改动,就是脏读
4.2.5 演示不可重复读
不可重复读是在一个事务里面,同一条sql语句,两次查询的结果不一致
1 开启AB窗口
2 设置A窗口的隔离级别是 读已提交
set session transaction isolation level read committed;
3 AB窗口都开启事务
4 在B中zs金额减少100,不要提交事务
5 在A中查询(避免了脏读)
6 在B中提交事务
7 在A中查看,发现数据改变,出现了不可重复读
mysql默认是可重复读,不会出现不可重复读
4.2.6 演示隔离级别串行化
1 开启AB窗口
2 设置A窗口的隔离级别是串行化
set session transaction isolation level serializable;
3 AB窗口都开启事务
4 在B中zs金额减少100,不要提交事务
5 在A中查询,会发现A中在等待B中的提交事务
6 在B中提交事务后,结果才能在A中查询
4.3 代码级别使用事务
// 开启手动管理事务
connection.setAutoCommit(false);
// 提交事务
connection.commit();
// 回滚事务
connection.rollback();
public class RoleSereviceImpl implements RoleService {
@Override
public int insertRoleService(Role role, String[] menuIdArr) {
Connection connection = DBUtil.getConnection();
RoleDao roleDao = new RoleDaoImpl(connection);
try {
// 开启事务
connection.setAutoCommit(false);
// 添加角色
long rid = roleDao.addRole(role);
// int i = 1 / 0;
// 添加中间表
int row = roleDao.addRoleAndMenu(rid, menuIdArr);
// 提交事务
connection.commit();
return row;
} catch (Exception e) {
try {
// 回滚事务
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection);
}
}
}

浙公网安备 33010602011771号