欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL 事务

程序员文章站 2022-03-16 08:25:19
...

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!再比如银行转账,从一个账户扣款,另一个账户收款,两者要么都执行,要么都不执行.
一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

事务的语句
开始事务: BEGIN TRANSACTION
提交事务: COMMIT TRANSACTION
回滚事务: ROLLBACK TRANSACTION
先来看一下传统方式向两个表插入数据存在的问题

tbl_user

MySQL 事务

tbl_address

MySQL 事务

现在向两个表插入数据
两个函数insertUserData(),insertAddressData();分别用于向两个表插入数据,sql语句分别为

insert into tbl_user(id,name,password,email)" + "values(10,'Tom','123456','aaa@qq.comgmail.com')";
insert into tbl_address(id,city,country,user_id)" + 
                            "values(2,'shanghai','china','10')";

执行后用户表没有问题,但是地址表会出现错误,导致只有一个能提交,这不是我们想看到的结果,需要进行改进.

package com.zmy.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

import com.sun.xml.internal.ws.client.sei.ValueSetter;

public class TransactionTest {
    public static Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp_db", "root", "password");
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return conn;
    }

    public static void insertUserData() {
        Connection conn = getConnection();
        try {
            String sql = "insert into tbl_user(id,name,password,email)" + "values(10,'Tom','123456','aaa@qq.comgmail.com')";
            Statement st = conn.createStatement();
            int count = st.executeUpdate(sql);
            System.out.println("向用户表中插入了 " + count + " 条记录");
            conn.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public static void insertAddressData(){
        Connection conn = getConnection();
        try{
            String sql = "insert into tbl_address(id,city,country,user_id)" + 
                            "values(3,'shanghai','china','10')";
            Statement st = conn.createStatement();
            int count = st.executeUpdate(sql);
            System.out.println("向地址表中插入了 " + count +" 条记录");
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        insertUserData();
        insertAddressData();
    }

}

事务插入数据

package com.zmy.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

import com.sun.xml.internal.ws.client.sei.ValueSetter;

public class TransactionTest {
    public static Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp_db", "root", "password");
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return conn;
    }

    public static void insertUserData(Connection conn) throws SQLException {
        String sql = "insert into tbl_user(id,name,password,email)" + "values(11,'Tom','123456','aaa@qq.comgmail.com')";
        Statement st = conn.createStatement();
        int count = st.executeUpdate(sql);
        System.out.println("向用户表中插入了 " + count + " 条记录");

    }

    public static void insertAddressData(Connection conn) throws SQLException {

        String sql = "insert into tbl_address(id,city,country,user_id)" + "values(3,'shanghai','china','10')";
        Statement st = conn.createStatement();
        int count = st.executeUpdate(sql);
        System.out.println("向地址表中插入了 " + count + " 条记录");

    }

    public static void main(String[] args) {
        Connection conn = null;
        try{
            conn = getConnection();
            conn.setAutoCommit(false);
            insertUserData(conn);
//          System.out.println("fuck");
            insertAddressData(conn);
            conn.commit();
        }catch(SQLException e){
            System.out.println("---------捕获SQL异常");
            e.printStackTrace();
            try{
                conn.rollback();
                System.out.println("--------事务回滚成功");
            }catch (Exception e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }
        }finally {
            try{
                if(conn!=null)
                    conn.close();
            }catch(Exception e3){
                e3.printStackTrace();
            }
        }
    }

}

此时可以插入数据,与数据表中主键不冲突,但是我们队sql语句进行更改后,
MySQL 事务

我们将第一个sql语句更改如下

String sql = "insert into tbl_user(id,name,password,email)" + "values(11,'Tom','123456','aaa@qq.comgmail.com')";

第二个sql语句不改变,此时只能一个可以插入,另一个无法插入
用事务处理的程序可以捕捉错误

MySQL 事务