• JDBC编程之事务处理


    -------------------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_passwordstu_info两张表不一致,本来小黄的stu_id005

    * 其中 insertStuPassword() 中已经插入了小黄的stu_id stu_pwd

    * insertStuInfo(),却因为输错了已经存在的 stu_id004 而无法插入

    * (即 一个插进去了,一个没有插进去,导致数据不一致)

    */

    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_passwordstu_info两张表不一致,本来小黄的stu_id005

    * 其中 insertStuPassword() 中已经插入了小黄的stu_id stu_pwd

    * insertStuInfo(),却因为输错了已经存在的 stu_id004 而无法插入

    * (即 一个插进去了,一个没有插进去,此时,可使事务回滚,使之都不插入,保持一致性)

    */

    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】

  • 相关阅读:
    JavaScript获取后台C#变量以及后台方法
    无刷新二级联动dropdownlist
    如何使用验证控件对DropDownList进行验证
    对某项目中Vuex用法的分析
    JavaScript中的深拷贝和浅拷贝
    Vue开发中的中央事件总线
    Vue项目中使用Vuex + axios发送请求
    html文件引用本地js文件出现跨域问题的解决方案
    数组的一些与遍历相关的方法总结
    《EMCAScript6入门》读书笔记——16.Generator函数的语法
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/6696300.html
Copyright © 2020-2023  润新知