日期:2014-05-16  浏览次数:20457 次

纯JDBC、Hibernate、Spring的AOP声明式事务管理小结

引言:

最近在中心的课程学到了Spring框架的声明式事务管理章节,今天敲个小例子将我目前所知道的三种事务的管理方式做一个简单的对比,顺便巩固一下基础知识。

三种方式:纯JDBC、Hibernate、?Spring的AOP声明式事务管理。

都用相同的需求:在一个方法中一次保存两个用户信息,需要保证都成功插入数据库。否则,一方异常或失败,数据回滚至原始状态。比较典型的示例应该是银行转账业务。

?

(一)纯JDBC

?

纯JDBC主要是在持久化操作之前将数据提交事务的模式更改为不自动提交,

关键代码:conn.setAutoCommit(false);?? 默认情况下,新连接处于自动提交模式。

在数据库关闭之前,如果一切操作正常,显示提交事务:conn.commit();

如果发生了异常,显示回滚事务:conn.rollback();

?

/**
 * conn.setAutoCommit(true|false)
 * 纯JDBC事务管理方式测试类
 */
package com.accp.transactiontest.test;

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

import com.accp.transactiontest.dao.base.ConnectionManager;
import com.accp.transactiontest.entity.Userinfo;

/**
 * @author Maxpin by 2011-07-25
 * 
 */
public class JDBCTest {
	/**
	 * 一次必须保存两个用户信息的方法
	 * 
	 * @param user1
	 *            用户1
	 * @param user2
	 *            用户2
	 */
	public static void saveUserinfo(Userinfo user1, Userinfo user2) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		try {
			// 获取数据库连接
			conn = ConnectionManager.getConnection();
			/*
			 * 设置不使用自动提交事务的方式
			 */
			conn.setAutoCommit(false);
			// 用户1
  			String sql = "insert into USERINFO(USERID,USERNAME,AGE,POINT) values(SEQ_ID.NEXTVAL,?,?,?)"; // 构建SQL语句
			pstmt = conn.prepareStatement(sql); // 创建命令对象
			pstmt.setString(1, user1.getUsername()); // 设置占位符参数
			pstmt.setShort(2, user1.getAge());
			pstmt.setString(3, user1.getPoint());
			pstmt.executeUpdate(); // 执行操作
			// 用户2
			sql = "insert into USERINFO(USERID,USERNAME,AGE,POINT) values(SEQ_ID.NEXTVAL,?,?,?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, user2.getUsername());
			pstmt.setShort(2, user2.getAge());
			pstmt.setString(3, user2.getPoint());
			pstmt.executeUpdate();
			/*
			 * 显示提交事务
			 */
			conn.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			try {
				/*
				 * 异常则显示回滚事务
				 */
				conn.rollback();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		} finally {
			// 关闭数据库连接
			ConnectionManager.closeConnection(null, pstmt, conn);
		}
	}

	/**
	 * main方法
	 * 
	 * @param args
	 * @throws ParseException
	 */
	public static void main(String[] args) throws ParseException {
		saveUserinfo(new Userinfo("程七七1", (short) 21, "1,3"), 
					 new Userinfo("程七七2", (short) 22, "4,2"));
	}
}

?

??

(二)Hibernate

?

Hibernate在持久化操作增、删、改时需要显示开启一个事务Transaction tx = session.beginTransaction(); (查询可不用)。

对于单独的事务管理方面来说,Hibernate同样需要显示提交事务tx.commit();,显示回滚事务tx.rollback();

?

如下Demo的main方法里的 用户2 的名字设置大于数据库中的字段最大值,因此会有异常。try/catch中捕获异常后显示回滚,正好做到需求描述的要求。

?

/**
 * tx.commit()|tx.rollback();
 * Hibernate事务管理方式测试类
 */
package com.accp.transactiontest.test;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.accp.transactiontest.dao.base.HibernateUtil;
import com.accp.transactiontest.entity.Userinfo;

/**
 * @author Maxpin by 2011-07-25
 * 
 */
public class HibernateTest {
	/**
	 * 一次必须保存两个用户信息的方法
	 * 
	 * @param user1
	 *            用户1
	 * @param user2
	 *            用户2
	 */
	public static void saveUserinfo(Userinfo user1, Userinfo user2) {
		Session session = HibernateUtil.getSession(); // 得到Session
		Transaction tx = session.beginTransaction();// 显示开启一个事务
		try {
			session.save(user1); // 保存用户1
			session.save(user2); // 保存用户2
			/*
			 * 显示提交事务
			 */
			tx.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			/*
			 * 异常则显示回滚事务
			 */</span>
			tx.rollback();
		} finally {