您的位置:首页 > 编程语言

JDBC编程之事务处理

2017-04-11 21:08 357 查看

-------------------siwuxie095

   

   

   

   

   

   

   

   

JDBC 编程之事务处理

   

   

   

数据库是一个多用户使用的共享资源,当多个用户并发的存取数据时,数据库

中就会可能发生多个用户同时存取同一数据的情况

   

若对并发操作不加控制,就可能会产生和读取不正确的数据,破坏数据的一致性

   

   

而事务正是并发控制的基本单位。所谓事务,是一个操作序列,这些操作要么都

执行,要么都不执行,是一个不可分割的工作单位

   

事务也是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据的一致性

   

   

在编程中,可以把数据库事务看做是一组 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)清理环境:关闭会话,关闭连接等操作,完成资源的清理工作

   

   

   

   

关于 数据库的准备,详见本人博客的分类:来一杯Java,

里面的 JDBC编程之数据准备

   

本人博客(任选其一)链接:

https://www.baidu.com/s?ie=UTF-8&wd=siwuxie095

   

   

   

   

   

   

   

   

【made by siwuxie095】

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: