Java 数据库事务处理

概要:

在执行多条SQL语句的时候,不能保证所有语句都执行成功。但是有些数据表间会存在着一些关联,例如:一条数据需要同时插入A表和B表中,也就是说A表和B表中的数据是一一对应的关系,如果在执行的过程中,对A表插入成功而对B表插入失败,两表中的对应关系失衡,将会对后面的工作造成很大的影响。为了解决类似的问题,就需要对数据库作一系列的修改,修改之间具有依赖关系,要么所有的语句全部执行成功,要么所有语句全部执行失败,这就是事务的概念。本实例将演示事务的提交与回滚。

| |目录

技术要点

提交和回滚事务的技术要点如下:

  • DatabaseMetaData的supportsTransactions()方法可以判断数据库是否支持事务。它的返回值类型为boolean,如果事务受支持,则返回true;否则返回false。

  • 数据库连接Connection对象默认是自动提交的。为了控制事务提交,则需在事务提交前,调用Connection的setAutoCommit(boolean autoCommit)方法关闭数据库连接的自动提交模式,其中参数autoCommit为true,表示启用自动提交模式;为false,表示禁用该模式。以后只有调用Connection的commit方法,才会将所有的操作提交到数据库。

  • Connection的rollback方法,执行回滚操作,其作用是如果一同进行操作的语句,有一条出现了错误,那么其他的语句也会操作无效。也就是说,要么一起都操作成功,要么就一起全部操作失败。使用此方法时,需要注意的是只能在setAutoCommit(false)的模式下使用。

代码实现

package net.xsoftlab.baike;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 判断数据库是否支持事务,如果支持,如何实现事务的提交与回滚。
 * MySQL中如果要使用事物,必须使用InnoDB存储引擎,在创建表时,后面加上ENGINE=InnoDB。
 * MySQL默认的存储引擎是MyISAM,不支持事物
 */
public class Transaction {
	/**
	 * 判断数据库是否支持事务
	 * 
	 * @param con
	 *            数据库的连接
	 * @return
	 */
	public static boolean supportTransaction(Connection con) {
		try {
			// 得到数据库的元数据
			DatabaseMetaData md = con.getMetaData();
			return md.supportsTransactions();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}
	/**
	 * 将一组SQL语句放在一个事务里执行,要某全部执行通过,要某全部不执行
	 * 
	 * @param con
	 *            数据库的连接
	 * @param sqls
	 *            待执行的SQL数组
	 * @throws Exception
	 */
	public static void Begin_Transaction(Connection con, String[] sqls)
			throws Exception {
		if (sqls == null) {
			return;
		}
		Statement sm = null;
		try {
			// 事务开始
			System.out.println("事务开始!");
			// 设置连接不自动提交,即用该连接进行的操作都不更新到数据库
			con.setAutoCommit(false);
			sm = con.createStatement();
			for (int i = 0; i < sqls.length; i++) {
				// 执行SQL语句,但是没更新到数据库
				sm.execute(sqls[i]);
			}
			// 提交,立即更新到数据库
			System.out.println("事务提交!");
			con.commit();
			System.out.println("事务结束!");
			// 事务结束
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			try {
				// 出现异常时,进行回滚,取消前面执行的操作
				System.out.println("事务执行失败,进行回滚!
");
				con.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			sm.close();
		}
	}
	public static void main(String[] args) throws Exception {
		String[] sqls = new String[3];
		sqls[0] = "UPDATE staff_info SET wage='2500' where name='lucy'";
		sqls[1] = "INSERT INTO staff_info (name, age, sex,address, depart, worklen,wage)"
				+ " VALUES ('haha', 27, 'w', 'china','Personnel','3','2000')";
		// 执行这条语句会引起错误,因为表staff_info不允许name列重复
		sqls[2] = "INSERT INTO userMess (name,password,nich,compass,sex,address,mail,phone) "
				+ "values ('nini','nini','mali','nini','w','changchun','ml@sina.com','1315588459');";
		Connection con = null;
		try {
			// 获得数据库连接
			con = getConnection();
			// 判断是否支持批处理
			boolean supportTransaction = Transaction.supportTransaction(con);
			System.out.println("支持事务? " + supportTransaction);
			if (supportTransaction) {
				// 执行事务
				Transaction.Begin_Transaction(con, sqls);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 关闭数据库连接
			con.close();
		}
		query_staff();
		query_userMess();
	}
	public static Connection getConnection() {// 数据库连接
		Connection con = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");// 加载Mysql数据驱动
			con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/myuser", "root", "123456");// 创建数据连接
		} catch (Exception e) {
			System.out.println("数据库连接失败");
		}
		return con;
	}
	public static void query_staff() {// 查询表staff_info
		Connection conect = getConnection();// 获取连接
		System.out.println("表staff_info的全部记录为:");
		try {
			String sql = "select * from staff_info";// 查询数据的sql语句
			Statement st = (Statement) conect.createStatement();// 创建Statement对象
			ResultSet rs = st.executeQuery(sql);// 返回查询数据的结果集
			while (rs.next()) {// 判断是否还有下一个数据
				// 根据字段名获取相应的值
				String name = rs.getString("name");
				int age = rs.getInt("age");
				String sex = rs.getString("sex");
				String address = rs.getString("address");
				String depart = rs.getString("depart");
				String worklen = rs.getString("worklen");
				String wage = rs.getString("wage");
				System.out.println(name + " " + age + " " + sex + " " + address
						+ " " + depart + " " + worklen + " " + wage);
			}
			System.out.println();
		} catch (SQLException e) {
			System.out.println("查询数据失败");
		}
	}
	public static void query_userMess() {// 查询表userMess
		Connection conect = getConnection();// 获取连接
		System.out.println("表userMess的全部记录为:");
		try {
			String sql = "select * from userMess";// 查询数据的sql语句
			Statement st = (Statement) conect.createStatement();// 创建Statement对象
			ResultSet rs = st.executeQuery(sql);// 返回查询数据的结果集
			while (rs.next()) {// 判断是否还有下一个数据
				// 根据字段名获取相应的值
				String name = rs.getString("name");
				String password = rs.getString("password");
				String nich = rs.getString("nich");
				String sex = rs.getString("sex");
				String address = rs.getString("address");
				String mail = rs.getString("mail");
				String phone = rs.getString("phone");
				System.out.println(name + " " + password + " " + nich + " "
						+ sex + " " + address + " " + mail + " " + phone);
			}
			System.out.println();
		} catch (SQLException e) {
			System.out.println("查询数据失败" + e.getMessage());
		}
	}
}

程序解读

  1. isTransaction()方法判断数据库是否支持事务。调用Connection的getMetaData方法获得数据库的DatabaseMetaData,再调用DatabaseMetaData的supportsTransactions方法判断数据库是否支持事务。

  2. Begin_Transaction()方法在事务中执行一组SQL语句。con.setAutoCommit(false)语句将数据库连接设置为不自动提交,然后用Statement对象依次执行SQL语句数组,如果所有执行都没有异常,表示事务中的所有操作都会执行成功,于是调用Connect的commit方法提交事务,将修改更新到数据库上。如果在用Statement执行SQL语句时,有一条执行发生异常,便调用Connect的rollback方法执行回滚,之前成功执行的SQL语句也将无效。

  3. 在main()方法中,创建并初始化一个String数组,数组里装有3个SQL语句,分别为在staff表插入、在staff_info表插入和更新staff_info表。

  4. query_staff()查询表staff_info,创建数据库连接Connection,创建Statement对象,执行executeQuery(sql);方法返回ResultSet结果集,然后根据字段名获取相应的值,打印在控制台上。

  5. query_userMess()查询表userMess。查询过程可以参考query_staff()方法。


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
资料加载中...
已关注 , 取消