保存点(savepoint)

保存点(Savepoint)提供了对事务更小粒度的控制方法,它代表一个逻辑事务点。在自动提交模式下,用户是不允许设置保存点的,神通数据库 JDBC驱动程序将会抛出异常。在非自动提交模式下,一个事务中可以设置多个保存点,这样在回滚的时候,可以回滚到指定的保存点,从事务开始到该保存点之间的操作依然有效。这就为事务处理提供了更多的灵活性。

保存点分为命名的和未命名的两种。未命名的用系统分配的 ID作为标识。下面的例子演示了保存点的使用:

package com.sun.cts.tests.jdbc.help_doc.shi_wu;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Properties;

import org.junit.Test;

import com.sun.cts.tests.jdbc.help_doc.ru_men.JDBCTest;

public class SavePointTest {
	private Connection con;
	private Statement stmt;
	public String DBUSER = "";
	public String DBPASSWD = "";
	public String DBURL = "";
	public String DBDRIVER = "";

	public void init() {
		Properties prop = new Properties();
		try {

			FileInputStream in = new FileInputStream(
					"." + File.separator + "testFile" + File.separator + "cts_env.properties");
			prop.load(in);
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//从配置文件读取
		DBUSER = prop.getProperty("DBUSER");
		DBPASSWD = prop.getProperty("DBPASSWD");
		DBURL = prop.getProperty("DBURL");
		DBDRIVER = prop.getProperty("DBDRIVER");
		try {
			Class.forName(DBDRIVER);
			con = DriverManager.getConnection(DBURL, DBUSER, DBPASSWD);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	@Test
	public void execute() {
		init();
		try {
			Statement stmt = con.createStatement();
			String sql;
			// 创建表
			sql = "CREATE TABLE TEMP"
					+ "(id INT not NULL,name varchar(255),PRIMARY KEY ( id ))";
			stmt.executeUpdate(sql);
			// 插入数据
			con.setAutoCommit(false);
			sql = "INSERT INTO TEMP VALUES(1,'shentong1')";
			int rows = stmt.executeUpdate(sql);
			// 设置保存点
			Savepoint sp1 = con.setSavepoint("SAVEPOINT_1");
			sql = "INSERT INTO TEMP VALUES (2,'shentong2')";
			rows = stmt.executeUpdate(sql);
			con.rollback(sp1);
			con.commit();
			// 查询数据
			sql = "SELECT COUNT(*) FROM TEMP";
			ResultSet rs = stmt.executeQuery(sql);
			rs.next();
			assertEquals(1, rs.getInt(1));
			
			// 删除表
			sql="DROP TABLE TEMP ";
			stmt.executeUpdate(sql);
				
			rs.close();
			stmt.close();
			con.close();
		} catch (Exception e) {
			fail(e.getMessage());
		}

	}

	public static void main(String[] args) {
		new SavePointTest().execute();;
	}
}

这样,数据库中只是增加了第一次插入的那条记录而已。这里要提请注意,在使用Savepoint之前,一定要把当前连接设置为非自动提交模式。

用户也可以调用Connection.releaseSavepoint()方法来释放设置过的保存点。一旦释放,保存点将立即变为无效,再试图调用Connection.rollback方法来引用这个保存点将导致SQLException被抛出。当全事务回滚之后,在事务中设置的所有保存点都变无效,试图引用也会导致异常。这里要注意另外一种情况,比如按顺序设置了保存点sp1,sp2,sp3,那么当用户回滚到sp2时,或将sp2释放掉,那么sp3保存点将不复存在,对sp3的释放或回滚操作将导致神通数据库 JDBC驱动程序抛出异常。