7. 使用 IDEA 连接数据库
- 选择数据源
- 连接数据库
- 选择数据库
- 查看:双击数据表
- 更新数据:绿色键头提交或快捷键
Ctrl+Enter
- SQL 语句
- 如连接失败,查看原因
8. 事务
- 概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功;
ACID 原则:
- 原子性(Atomic);
- 一致性(Consist);
- 隔离性(Isolated);
- 持久性(Durable)。
隔离性问题
- 脏读:指一个事务,读取了另外一个事务未提交的数据;
- 不可重复读:指在一个事务内,读取表中的某一行数据,多次读取结果不同;
- 虚读(幻读):指在一个事务内,读取到了别的事务插入的数据,导致前后读取不一致。
代码测试
-- 创建账户表
CREATE TABLE `account`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(40),
`money` FLOAT
);
-- 插入测试数据
insert into `account`(`name`,`money`) values('A',1000);
insert into `account`(`name`,`money`) values('B',1000);
insert into `account`(`name`,`money`) values('C',1000);
-
当 JDBC 程序向数据库,获得一个
Connection
对象时,默认情况下,这个Connection
对象,会 自动向数据库提交 在它上面发送的 SQL 语句; -
若要关闭这种默认提交方式,让多条 SQL 在一个事务中执行,可使用下列的 JDBC 控制事务语句;
- 开启事务:
Connection.setAutoCommit(false);
- 事务自动关闭;
- 回滚事务:
Connection.rollback();
- 默认自动回滚;
- 提交事务:
Connection.commit();
- 开启事务:
-
测试 1:模拟转账成功时的业务场景
package com.xxx.demo04;
import com.xxx.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
// 模拟转账
public class TestTransaction01 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 通知数据库开启事务(start transaction)
conn.setAutoCommit(false);
String sql1 = "update `account` set `money` = `money`-100 where `name`='A';";
String sql2 = "update `account` set `money` = `money`+100 where `name`='B';";
// 执行sql1
st = conn.prepareStatement(sql1);
st.executeUpdate();
// 执行sql2
st = conn.prepareStatement(sql2);
st.executeUpdate();
// SQL都执行完毕,通知数据库提交事务(commit)
conn.commit();
System.out.println("操作成功!");
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(conn, st, null);
}
}
}
- 测试 2:模拟程序异常,导致一部分 SQL 执行失败(自动回滚事务)
package com.xxx.demo04;
import com.xxx.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
// 模拟转账
public class TestTransaction02 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 通知数据库开启事务(start transaction)
conn.setAutoCommit(false);
String sql1 = "update `account` set `money` = `money`-100 where `name`='A';";
String sql2 = "update `account` set `money` = `money`+100 where `name`='B';";
// 执行sql1
st = conn.prepareStatement(sql1);
st.executeUpdate();
// 模拟执行完sql1后,程序出现异常,事务无法正常提交,数据库会自动执行回滚操作
int x = 1 / 0;
// 执行sql2
st = conn.prepareStatement(sql2);
st.executeUpdate();
// SQL都执行完毕,通知数据库提交事务(commit)
conn.commit();
System.out.println("操作成功!");
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(conn, st, null);
}
}
}
- 测试 3:模拟程序异常,导致一部分 SQL 执行失败(手动通知回滚事务)
package com.xxx.demo04;
import com.xxx.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
// 模拟转账
public class TestTransaction03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 通知数据库开启事务(start transaction)
conn.setAutoCommit(false);
String sql1 = "update `account` set `money` = `money`-100 where `name`='A';";
String sql2 = "update `account` set `money` = `money`+100 where `name`='B';";
// 执行sql1
st = conn.prepareStatement(sql1);
st.executeUpdate();
// 模拟执行完sql1后,程序出现异常,事务无法正常提交
int x = 1 / 0;
// 执行sql2
st = conn.prepareStatement(sql2);
st.executeUpdate();
// SQL都执行完毕,通知数据库提交事务(commit)
conn.commit();
System.out.println("操作成功!");
} catch (SQLException e) {
// 捕获到异常,手动通知数据库,执行回滚事务的操作
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtils.release(conn, st, null);
}
}
}
网友评论