JDBC中的事物处理
一项事物是由一个或是多个操作所组成的一个不可分割的工作单元。我们通过提交commit()或是回退rollback()来结束事务的操作。
JDBC的事物处理包括三个方面:
1:自动提交模式;
2:事务隔离模式;
3:存储点;
数据库并发操作过程中会出现以下三种不确定的情况:
脏读。当应用程序使用了被另一个应用程序修改过的数据,而这个数据处于未提交状态时,就会发生脏读。第二个应用程序随后会请求回滚被其修改的数据。第一个事务使用的数据就会被损坏,或者“变脏”。
单读。当一个事务获得了数据,而该数据随后被一个单独的事务所更改时,若第一个事务再次读取更改后的数据,就会发生单读。这样,第一个事务进行了一个单读。
虚读。当事务通过某种查询获取了数据,另一个事务修改了部分该数据,原来的事务第二次获取该数据时,就会发生虚读。第一个事务现在会有不同的结果集,它可能包含虚读。\
我们可以设置事物隔离级别来解决:
TRANSACTION_READ_UNCOMMITTED | ur | 就是俗称“脏读”(dirty read),在没有提交数据时能够读到已经更新的数据 |
TRANSACTION_READ_COMMITTED | cs | 在一个事务中进行查询时,允许读取提交前的数据,数据提交后,当前查询就可以读取到数据。update数据时候并不锁住表 |
TRANSACTION_REPEATABLE_READ | rs | 在一个事务中进行查询时,不允许读取其他事务update的数据,允许读取到其他事务提交的新增数据 |
TRANSACTION_SERIALIZABLE | rr | 在一个事务中进行查询时,不允许任何对这个查询表的数据修改。 |
存储点:
作用: 在事物进行中的某个位置设置一个标识,这样事物就可以在不影响这个存储点之前的工作的情况下进行回滚,将应用程序返回到一个已知的状态。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import javax.naming.spi.DirectoryManager; public class JDBC { public static void main(String args[]){ String dirverName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/test"; String userName = "root"; String userPassword = "1"; Connection conn = null; PreparedStatement pst = null; ResultSet rs = null; Savepoint sp = null; try { Class.forName(dirverName); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { conn = DriverManager.getConnection(url, userName, userPassword); //将事物自动提交设置为false conn.setAutoCommit(false); //设置事物的隔离级别 conn.setTransactionIsolation(conn.TRANSACTION_READ_COMMITTED); String sql = "create table users(id int primary key, name varchar(50))"; pst = conn.prepareStatement(sql); pst.execute(); //事物提交 conn.commit(); pst.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } try { //设置存储点 sp = conn.setSavepoint(); String sql = "insert into users values(1,'Jack')"; pst = conn.prepareStatement(sql); pst.executeUpdate(sql); conn.commit(); //如果成功提交释放存储点 conn.releaseSavepoint(sp); pst.close(); conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block System.out.println("失败。。"); e.printStackTrace(); try { System.out.println("失败。。"); //回滚放到存储点 conn.rollback(sp); pst.close(); conn.close(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } }