JDBC事务回滚
这个案例使用的是mysql数据库

  1. 事务的回滚主要是用在增删改里面
  2. 由于事务回滚操作自能回滚同一连接内的数据
  3. 在jdbc的使用是一样的,唯一不同的是必须使用同一个连接
  4. 所有在这里使用ThreadLocal容器去保存connection连接
  5. 在业务层进行事务操作
  6. 开启事务,成功就提交,遇到异常就回滚
  • 实体类
package panxg_08_01;

public class Student {

	private Integer stu_id;
	private String stu_name;
	private String stu_password;
	private String stu_sex;
	private String stu_age;
	public Student() {
		super();
	}
	public Student(Integer stu_id, String stu_name, String stu_password, String stu_sex, String stu_age) {
		super();
		this.stu_id = stu_id;
		this.stu_name = stu_name;
		this.stu_password = stu_password;
		this.stu_sex = stu_sex;
		this.stu_age = stu_age;
	}
	public Integer getStu_id() {
		return stu_id;
	}
	public void setStu_id(Integer stu_id) {
		this.stu_id = stu_id;
	}
	public String getStu_name() {
		return stu_name;
	}
	public void setStu_name(String stu_name) {
		this.stu_name = stu_name;
	}
	public String getStu_password() {
		return stu_password;
	}
	public void setStu_password(String stu_password) {
		this.stu_password = stu_password;
	}
	public String getStu_sex() {
		return stu_sex;
	}
	public void setStu_sex(String stu_sex) {
		this.stu_sex = stu_sex;
	}
	public String getStu_age() {
		return stu_age;
	}
	public void setStu_age(String stu_age) {
		this.stu_age = stu_age;
	}
	@Override
	public String toString() {
		return "Student [stu_id=" + stu_id + ", stu_name=" + stu_name + ", stu_password=" + stu_password + ", stu_sex="
				+ stu_sex + ", stu_age=" + stu_age + "]";
	}
	
}
  • jdbc连接类
package panxg_08_01;

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

/**
 * JDBC事务
 * 
 * @author ASUS
 * @param <T>
 * @param <T>
 *
 */
public class JDBCTransaction<T> {

	private final static String DRIVER = "com.mysql.jdbc.Driver";
	private final static String URL = "jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8";
	private final static String USERNAME = "root";// 账号
	private final static String PASSWORD = "123456";// 密码
	private static PreparedStatement pst = null; // 创建执行SQL命令对象 安全,参数绑定使用的是占位符
	private static ResultSet rs = null; // 结果集对象
	// 存放一个连接时的容器
	private static ThreadLocal<Connection> con = new ThreadLocal<Connection>();
	private static Class cs;

	/**
	 * 加载驱动
	 */
	static {
		try {
			Class.forName(DRIVER);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 无参构造方法
	 */
	public JDBCTransaction() {
		// 创建连接
		createConnection();
	}

	/**
	 * 有参构造
	 */
	public JDBCTransaction(Class<T> c) {
		cs = c;
		// 创建连接
		createConnection();
	}

	/**
	 * 创建连接 存放到连接容器里面
	 * @return 
	 */
	private static Connection createConnection() {
		try {
			Connection connection = con.get();
			if (connection == null) {
				return DriverManager.getConnection(URL, USERNAME, PASSWORD);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return con.get();
	}

	/**
	 * 更新方法 开启事务
	 * @throws SQLException 
	 */
	public static Integer executeUpdateTransaction(String sql, Object... params) throws SQLException {
		// 获取连接
		Connection connection = con.get();
		Integer executeUpdate = 0;
		try {
			// 创建执行对象
			pst = connection.prepareStatement(sql);
			// 绑定数据
			bindPlaceholders(params);
			// 执行sql语句
			executeUpdate = pst.executeUpdate();
		}finally {
			// 关闭当前连接
			//不是真正的关闭
			//当我们事务回滚或者提交的时候才进行关闭
			closeConnection(connection);
		}
		return executeUpdate;
	}

	/**
	 * 绑定占位符
	 * 
	 * @param obj
	 */
	private static void bindPlaceholders(Object[] params) {
		try {
			// 如果不为空进行绑定
			if (params != null) {
				int i = 1;
				// 遍历数组参数
				for (Object object : params) {
					// 绑定到ps执行对象,数据库下标从1开始,
					pst.setObject(i++, object);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 开启事务
	 */
	public static void openTransaction() {
		System.out.println("开启事务");
		// 获取连接对象
		Connection connection = con.get();
		if (connection != null) {
			throw new RuntimeException("事务已经开启");
		}
		// 创建连接
		connection = createConnection();
		try {
			// 设置是否自动提交事务(默认为true,默认提交)
			//false(手动提交)connection.commit();
			connection.setAutoCommit(false);
			// 存入容器
			con.set(connection);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 提交事务
	 */
	public static void commitTransaction() {
		System.out.println("提交事务");
		// 从容器获取连接对象
		Connection connection = con.get();
		if (connection == null) {
			throw new RuntimeException("事务已经提交");
		}
		try {
			// 提交事务
			connection.commit();
			// 关闭连接
			connection.close();
			// 清空容器连接
			con.remove();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 事务回滚
	 */
	public static void rollbackTransaction() {
		System.out.println("事务回滚");
		Connection connection = con.get();
		if (connection == null) {
			throw new RuntimeException("事务已经回滚");
		}
		try {
			// 事务回滚
			connection.rollback();
			// 关闭连接
			connection.close();
			// 清空容器连接
			con.remove();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 关闭连接 不是正真正的关闭容器里面的连接对象 而是关闭真正使用的
	 * 
	 */
	public static void closeConnection(Connection connection) {
		Connection connection2 = con.get();
		// 結果集为空
		rs = null;
		// 关闭执行对象
		try {
			if (pst != null) {
				pst.close();
				pst = null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			// 如果传过来的连接没有关闭就把他关闭了
			if (connection2 == null) {
				connection.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			// 如果传过来的连接没有关闭就把他关闭了
			if (connection2 != connection) {
				connection.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}
}
  • 测试类
package panxg_08_01;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
 * 	事务回滚:
 * 		事务回滚必须使用一个连接,就是connection连接,就像是指new一个对象
 * 		事务回滚只能回滚一个连接里面的信息
 * 		事务分为:
 * 			开启事务,提交事务。
 * 			开启事务,回滚事务(中途遇见异常)。
 * 	
 * @author ASUS
 *
 */
public class JDBCTransactionTest {

	public static void main(String[] args) {
		String sql1 = new String("update student a set stu_name=? where stu_id=?");
		String sql2 = new String("update student b set stu_name=? where stu_id=?");
		String sql3 = new String("update student as set stu_name=? where stu_id=?");
		Map<String, String[]> map = new HashMap<String, String[]>();
		map.put(sql1, new String[] { "潘先生1", "1" });
		map.put(sql2, new String[] { "潘先生2", "2" });
		map.put(sql3, new String[] { "潘先生3", "3" });
		System.out.println("修改条数:"+studentService.updateByStuId(map));
	}
}

/**
 * 	事务回滚主要写在业务层
 * 	
 * @author ASUS
 *
 */
class studentService {

	public static Integer updateByStuId(Map<String, String[]> map) {
		Integer jugde = 0;
		// 开启事务
		JDBCTransaction.openTransaction();
		try {
			for (Entry<String, String[]> mapEntry : map.entrySet()) {
				System.out.println(mapEntry.getKey() + "\t" + mapEntry.getValue());
				jugde = jugde + JDBCTransaction.executeUpdateTransaction(mapEntry.getKey(), mapEntry.getValue());
			}
			// 提交事务
			JDBCTransaction.commitTransaction();
		} catch (Exception e) {
			System.out.println(e.getMessage());
			// 事务回滚
			JDBCTransaction.rollbackTransaction();
			jugde = 0;
		}
		return jugde;

	}

}