事务ACID特性
序号特性描述
1原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
4持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响




Connection操作事务的相关方法
序号方法作用
1void setAutoCommit(boolean autoCommit)设置事务是否自动提交
如果设置为false,表示手动提交事务。
2void commit() ()手动提交事务
3void rollback()回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)
4Savepoint setSavepoint(String name)在当前事务中创建一个保存点


1、使用事务

package com.rk.db.g_transaction;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.rk.db.utils.JDBCUtil;

/**
 * // 转账,使用事务
 * @author RK
 *
 */
public class Demo01
{
	public static void main(String[] args)
	{
		Connection conn = null;
		try
		{
			conn = JDBCUtil.getConnection();
			// 1、设置事务为手动提交
			conn.setAutoCommit(false);

			boolean flag = true; //表示是否出现SQL异常
			transferMoney(conn, 100, "张三", "李四",flag);
		}
		catch (SQLException e)
		{
			System.out.println("转账失败!");
			try
			{
				// 2、 出现异常,需要回滚事务
				conn.rollback();
				System.out.println("回滚操作成功!!!");
			}
			catch (SQLException ex)
			{
				ex.printStackTrace();
			}
		}
		finally
		{
			// 3、所有的操作执行成功, 提交事务
			try
			{
				conn.commit();
				System.out.println("执行完毕!");
			}
			catch (SQLException e)
			{
				e.printStackTrace();
			}
			JDBCUtil.closeQuietly(conn);
		}
	}

	/**
	 * 模拟银行转账
	 * @param conn 数据库连接
	 * @param moneyNum 转账的金额
	 * @param userAdd 收到Money的用户
	 * @param userSub 支出Money的用户
	 * @param flag 是否模拟SQL Exception异常,true表示出现,false表示不出现
	 * @throws SQLException
	 */
	private static void transferMoney(Connection conn, 
			long moneyNum, String userAdd, String userSub,
			boolean flag) throws SQLException
	{
		PreparedStatement pstmtAdd = null;
		PreparedStatement pstmtSub = null;

		try
		{
			String sqlAddMoney = "update T_Bank set money=money+? where username=?";
			pstmtAdd = conn.prepareStatement(sqlAddMoney);
			pstmtAdd.setLong(1, moneyNum);
			pstmtAdd.setString(2, userAdd);
			pstmtAdd.executeUpdate();
			
			if(flag)
			{
				throw new SQLException("模拟SQL执行出错");
			}

			String sqlSubMoney = "update T_Bank set money=money-? where username=?";
			pstmtSub = conn.prepareStatement(sqlSubMoney);
			pstmtSub.setLong(1, moneyNum);
			pstmtSub.setString(2, userSub);
			pstmtSub.executeUpdate();
		}
		finally
		{
			JDBCUtil.closeQuietly(pstmtAdd);
			JDBCUtil.closeQuietly(pstmtSub);
		}

	}
}



2、使用事务,回滚到指定的代码段

package com.rk.db.g_transaction;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

import com.rk.db.utils.JDBCUtil;

/**
 * // 转账,使用事务, 回滚到指定的代码段
 * @author RK
 *
 */
public class Demo02
{
	public static void main(String[] args)
	{
		Connection conn = null;
		Savepoint sp = null;
		try
		{
			conn = JDBCUtil.getConnection();
			// 1、设置事务为手动提交
			conn.setAutoCommit(false);

			transferMoney(conn, 1000, "李四", "张三",false);
			
			// 如果失败,回滚到这个位置
			sp = conn.setSavepoint();
			
			boolean flag = true; //表示是否出现SQL异常
			transferMoney(conn, 500, "张三", "李四",flag);
		}
		catch (SQLException e)
		{
			System.out.println("转账失败!");
			try
			{
				// 2、 出现异常,需要回滚 (回滚到指定的代码段)
				conn.rollback(sp);
				System.out.println("回滚到指定位置操作成功!!!");
			}
			catch (SQLException ex)
			{
				ex.printStackTrace();
			}
		}
		finally
		{
			// 3、所有的操作执行成功, 提交事务
			try
			{
				conn.commit();
				System.out.println("执行完毕!");
			}
			catch (SQLException e)
			{
				e.printStackTrace();
			}
			JDBCUtil.closeQuietly(conn);
		}
	}

	/**
	 * 模拟银行转账
	 * @param conn 数据库连接
	 * @param moneyNum 转账的金额
	 * @param userAdd 收到Money的用户
	 * @param userSub 支出Money的用户
	 * @param flag 是否模拟SQL Exception异常,true表示出现,false表示不出现
	 * @throws SQLException
	 */
	private static void transferMoney(Connection conn, 
			long moneyNum, String userAdd, String userSub,
			boolean flag) throws SQLException
	{
		PreparedStatement pstmtAdd = null;
		PreparedStatement pstmtSub = null;

		try
		{
			String sqlAddMoney = "update T_Bank set money=money+? where username=?";
			pstmtAdd = conn.prepareStatement(sqlAddMoney);
			pstmtAdd.setLong(1, moneyNum);
			pstmtAdd.setString(2, userAdd);
			pstmtAdd.executeUpdate();
			
			if(flag)
			{
				throw new SQLException("模拟SQL执行出错");
			}

			String sqlSubMoney = "update T_Bank set money=money-? where username=?";
			pstmtSub = conn.prepareStatement(sqlSubMoney);
			pstmtSub.setLong(1, moneyNum);
			pstmtSub.setString(2, userSub);
			pstmtSub.executeUpdate();
		}
		finally
		{
			JDBCUtil.closeQuietly(pstmtAdd);
			JDBCUtil.closeQuietly(pstmtSub);
		}

	}
}