数据库是一个多用户使用的共享资源,当多个用户并发的存取数据时,数据库
中就会可能发生多个用户同时存取同一数据的情况
若对并发操作不加控制,就可能会产生和读取不正确的数据,破坏数据的一致性
而事务正是并发控制的基本单位。所谓事务,是一个操作序列,这些操作要么都
执行,要么都不执行,是一个不可分割的工作单位
事务也是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据的一致性
在编程中,可以把数据库事务看做是一组 SQL 语句,这组 SQL 语句是一个逻辑工作
单元,它们是不可分割的,其执行结果应该作为一个整体,永久性的修改数据库内容,
或 作为一个整体,取消对数据库的修改
事务的四个基本特征
(1)原子性
事务中包含的操作,看做是一个逻辑单元,这个逻辑单元中的操作
要么全部成功,要么全部失败
这也意味着事务中的所有元素,作为一个整体 提交 或 回滚
「事务的所有元素是不可分割的,是一个完整的操作」
(2)一致性
事务开始之前,和事务结束以后,数据库都处于一致性状态,数据库
的完整性约束,没有被破坏
(3)隔离性
对数据库进行修改的多个事务,是彼此隔离的
即 事务必须是独立的,不应该以任何形式影响其他事务
(4)持久性
事务完成之后,对于系统的影响是永久的,该修改真实的修改了
数据库,即使系统出现故障,也会一直保留
与事务相关的 SQL 语句:
开始事务:BEGIN TRANSACTION
提交事务:COMMIT TRANSACTION
回滚事务:ROLLBACK TRANSACTION
程序示例:
首先下载 MySQL 的 JDBC 驱动,下载链接:
https://dev.mysql.com/downloads/connector/j/
mysql-connector-java-5.1.41.zip 解压后一览:
工程名:JDBCTest
包名:com.siwuxie095.jdbc
类名:TransactionTest.java、TransactionTestX.java
打开资源管理器,在工程 JDBCTest 文件夹下,创建一个文件夹:lib,
在其中放入:mysql-connector-java-5.1.41-bin.jar
工程结构目录如下:
选择 mysql-connector-java-5.1.41-bin.jar,右键->Build Path->Add to Build Path
此时,工程结构目录一览:
TransactionTest.java:
package com.siwuxie095.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
//实际上将数据库信息硬编码到java代码中,不可取
public class TransactionTest {
public static Connection getConnection() {
Connection conn=null;
try {
Class.forName(“com.mysql.jdbc.Driver”);
conn=DriverManager.getConnection(“jdbc:mysql://localhost:3306/sims_db”,“root”,“8888”);
} catch (Exception e) {
e.printStackTrace();
System.err.println(“加载数据库失败…”);
}
return conn;
}
public static void insertStuPassword() {
Connection conn=getConnection();
try {
String sql=“insert into stu_password(stu_id,stu_pwd)”+
“values(‘005’,‘005’)”;
Statement st=conn.createStatement();
int count=st.executeUpdate(sql);
System.out.println(“向stu_password表中插入了 “+count+” 条记录”);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void insertStuInfo() {
Connection conn=getConnection();
try {
/**
-
stu_id是主键,出现异常:
-
即stu_password和stu_info两张表不一致,本来小黄的stu_id是005
-
其中 insertStuPassword() 中已经插入了小黄的stu_id 和 stu_pwd
-
而 insertStuInfo(),却因为输错了已经存在的 stu_id:004 而无法插入
-
(即 一个插进去了,一个没有插进去,导致数据不一致)
*/
String sql=“insert into stu_info(stuid,stu_name,stu_sex,stu_scademic,stu_major)”+
“values(‘004’,‘小黄’,‘男’,‘工程学院’,‘土木工程’)”;
Statement st=conn.createStatement();
int count=st.executeUpdate(sql);
System.out.println(“向stu_info表中插入了 “+count+” 条记录”);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
insertStuPassword();
insertStuInfo();
}
}
TransactionTestX.java:
package com.siwuxie095.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
//实际上将数据库信息硬编码到java代码中,不可取
public class TransactionTestX {
public static Connection getConnection() {
Connection conn=null;
try {
Class.forName(“com.mysql.jdbc.Driver”);
conn=DriverManager.getConnection(“jdbc:mysql://localhost:3306/sims_db”,“root”,“8888”);
} catch (Exception e) {
e.printStackTrace();
System.err.println(“加载数据库失败…”);
}
return conn;
}
//将SQLException抛给上层调用方法进行处理
public static void insertStuPassword(Connection conn) throws SQLException {
String sql = “insert into stu_password(stu_id,stu_pwd)” + “values(‘005’,‘005’)”;
Statement st = conn.createStatement();
int count = st.executeUpdate(sql);
System.out.println(“向stu_password表中插入了 " + count + " 条记录”);
}
public static void insertStuInfo(Connection conn) throws SQLException {
/**
-
stu_id是主键,出现异常:
-
即stu_password和stu_info两张表不一致,本来小黄的stu_id是005
-
其中 insertStuPassword() 中已经插入了小黄的stu_id 和 stu_pwd
-
而 insertStuInfo(),却因为输错了已经存在的 stu_id:004 而无法插入
-
(即 一个插进去了,一个没有插进去,此时,可使事务回滚,使之都不插入,保持一致性)
*/
String sql = “insert into stu_info(stu_id,stu_name,stu_sex,stu_academic,stu_major)”
- “values(‘004’,‘小黄’,‘男’,‘工程学院’,‘土木工程’)”;
Statement st = conn.createStatement();
int count = st.executeUpdate(sql);
System.out.println(“向stu_info表中插入了 " + count + " 条记录”);
}
//在main方法中进行事务回滚
public static void main(String[] args) {
Connection conn=null;
try {
conn=getConnection();
conn.setAutoCommit(false);//禁止事务自动提交
insertStuPassword(conn);
insertStuInfo(conn);
conn.commit();//提交事务
} catch (SQLException e) {
System.out.println(“=捕获到 SQL 异常=”);
e.printStackTrace();
try {
conn.rollback();//回滚事务
System.out.println(“=事务回滚成功”);
} catch (Exception e2) {
e2.printStackTrace();
}
}finally {
try {
if (conn!=null) {
conn.close();
}
} catch (Exception e3) {
e3.printStackTrace();
}
}
}
}
对比 TransactionTest.java 和 TransactionTestX.java:
「事务处理使数据库的一致性没有被破坏」
注意:高版本的 JDBC 驱动需要指明是否进行 SSL 连接
即 加上:?characterEncoding=utf8&useSSL=false
或:
即 加上:?useUnicode=true&characterEncoding=utf-8&useSSL=false
总结 JDBC 编程流程:
(1)加载驱动:加载 JDBC 驱动程序
(2)打开连接:打开一个数据库连接
(3)执行查询:创建一个会话对象,执行增删改查等操作
(4)处理结果:处理查询的结果
(5)清理环境:关闭会话,关闭连接等操作,完成资源的清理工作
转载:https://www.cnblogs.com/siwuxie095/p/6696300.html