JDBC控制事务

概念

事务(Transaction)是访问并可能更新数据库中各类 数据项的一个程序执行单元(unit)。事务一般由 高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的 用户程序的执行所引发,并用形如begin transaction和end transaction语句(或 函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操做组成。
例如:在 关系数据库中,一个事务能够是一条SQL语句,一组SQL语句或整个程序。

特性

事务是恢复和 并发控制的基本单位。
事务应该具备4个属性:原子性、一致性、隔离性、持久性。这四个属性一般称为ACID特性。
原子性(atomicity)。一个事务是一个不可分割的工做单位,事务中包括的诸操做要么都作,要么都不作。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另外一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其余事务干扰。即一个事务内部的操做及使用的数据对并发的其余事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其余操做或故障不该该对其有任何影响。
 

定义

在数据库操做中,为了有效保证并发读取数据的正确性,提出的 事务隔离级别

问题的提出

数据库是要被广大客户所共享访问的,那么在数据库操做过程当中极可能出现如下几种不肯定状况。

更新丢失

两个事务都同时更新一行数据,一个事务对数据的更新把另外一个事务对数据的更新覆盖了。这是由于系统没有执行任何的锁操做,所以并发事务并无被隔离开来。

脏读

一个事务读取到了另外一个事务未提交的数据操做结果。这是至关危险的,由于极可能全部的操做都被 回滚

不可重复读

不可重复读(Non-repeatable Reads):一个事务对同一行数据重复读取两次,可是却获得了不一样的结果。
包括如下状况:
(1) 虚读:事务T1读取某一数据后,事务T2对其作了修改,当事务T1再次读该数据时获得与前一次不一样的值。
(2)  幻读(Phantom Reads):事务在操做过程当中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺乏了第一次查询中出现的数据(这里并不要求两次查询的 SQL语句相同)。这是由于在两次查询过程当中有另一个事务插入数据形成的。
 

解决方案

为了不上面出现的几种状况,在标准 SQL规范中,定义了4个事务隔离级别,不一样的隔离级别对事务的处理不一样。

未受权读取

也称为读未提交(Read Uncommitted):容许脏读取,但不容许更新丢失。若是一个事务已经开始写数据,则另一个事务则不容许同时进行写操做,但容许其余事务读此行数据。该隔离级别能够经过“排他写锁”实现。

受权读取

也称为读提交(Read Committed):容许 不可重复读取,但不容许脏读取。这能够经过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务容许其余事务继续访问该行数据,可是未提交的写事务将会禁止其余事务访问该行。

可重复读取(Repeatable Read)

可重复读取(Repeatable Read):禁止 不可重复读取和脏读取,可是有时可能出现幻读数据。这能够经过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但容许读事务),写事务则禁止任何其余事务。

序列化(Serializable)

序列化(Serializable):提供严格的事务隔离。它要求事务 序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅经过“行级锁”是没法实现事务序列化的,必须经过其余机制保证新插入的数据不会被刚执行查询操做的事务访问到。
隔离级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。对于多数应用程序,能够优先考虑把 数据库系统的隔离级别设为Read Committed。它可以避免脏读取,并且具备较好的并发性能。尽管它会致使 不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,能够由应用程序采用 悲观锁乐观锁来控制。
 
mysql中默认事务的隔离级别是Repeatable Read,事务的隔离级别越高,数据库性能越差。
 

JDBC中事务的使用

conn.setAutoCommit(0);//修改系统非自动提交。

conn.commit();//事务提交

conn.rollback();//事务回滚

SavePoint sp=con.setSavePoint();//设置保存点

conn.rollback(sp);//返回保存点

conn.setTransactionIsolation();//设置隔离级别

conn.getTransactionIsolation();//获取隔离级别

其中隔离级别的设置以下:

设定事务的隔离级别:con.setTransactionIsolation(Connection.isolationLevel);
四种隔离级别: 
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);//最底级别:只保证不会读到非法数据,上述3个问题有可能发生 
con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); //默认级别:能够防止脏读 
con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);//能够防止脏读和不可重复读取 
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); //最高级别:防止上述3种状况,事务串行执行

 

 简单的用例:java

package com.netease.class1;

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

import org.apache.commons.dbcp.BasicDataSource;

import com.mysql.jdbc.PreparedStatement;

public class work_4 {
    private static String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    private static String DB_URL = "jdbc:mysql://10.120.177.10:3306/datebaseclass";
    private static String USER = "test";
    private static String PASS = "test";

    public static void main(String[] args) throws ClassNotFoundException {
        work4();
    }

    public static void work4() {
        Connection conn = null;
        PreparedStatement ptmt = null;
        ResultSet rs = null;
        try {
            // 1
            Class.forName(JDBC_DRIVER);
            // 2
            conn = (Connection) DriverManager.getConnection(DB_URL, USER, PASS);
            // 3
            conn.setAutoCommit(false);
            ptmt = (PreparedStatement) conn
                    .prepareStatement("update Product set Inventory=Inventory-1 where ProductName = 'bag'");
            ptmt.execute();
            ptmt = (PreparedStatement) conn
                    .prepareStatement("INSERT INTO `Order` (buyer, ProductName) VALUES ('XiaoMing', 'bag')");
            ptmt.execute();
            conn.commit();

        } catch (ClassNotFoundException e) {
            // Class没有发现异常
            System.out.println(e.toString());
        } catch (SQLException e) {
            // Class没有发现异常
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {

                    System.out.println(e.toString());
                }
            }
            System.out.println(e.toString());
        } finally {

            try {
                if (conn != null) {
                    conn.close();
                }
                if (ptmt != null) {
                    ptmt.close();
                }
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                System.out.println(e.toString());
            }
        }

    }
}
相关文章
相关标签/搜索