Spring的事務管理入門:程式設計式事務管理(TransactionTemplate)

韓師學子--胖佳發表於2019-03-12

 Spring的事務管理入門:程式設計式事務管理(TransactionTemplate)


轉載:https://blog.csdn.net/zq9017197/article/details/6321391

 

Spring可以支援程式設計式事務和宣告式事務。

Spring使用事務管理器,每個不同平臺的事務管理器都實現了介面:PlatformTransactionManager

此介面是事務管理的核心,提供了三個需要實現的函式:
 

commit(TransactionStatus status) ;   
getTransaction(TransactionDefinition definition) ;   
rollback(TransactionStatus status) ;

如果我們使用的是JDBC來處理事務,那麼這個事務管理器就是DataSourceTransactionManager。

通過Spring文件查詢到這個類,發現其需要DataSource這個類。也就是隻要實現了javax.sql.DataSource這個介面的類,都可以作為引數傳入到DataSourceTransactionManager。

 然後,找到 包org.springframework.transaction.support中的 TransactionTemplate。

發現TransactionTemplate中有一個重要的方法:

execute(TransactionCallback action) ;

就是利用這個方法,我們可以在這個方法中新增事務。

這個方法需要傳入引數 TransactionCallback。

TransactionCallback,顧名思義,就是事務回撥然後查到TransactionCallback。

發現這是一個介面(這也必須是介面,因為任務都是自己具體定義的)

裡面只有一個方法:

doInTransaction(TransactionStatus status) ; 

很明顯,就是在一個事務中需要做的事情都包括這這個方法中了。

而這個doInTransaction 又傳入了一個引數,這次是 TransactionStatus,繼續顧名思義,也就是事務狀態。

查詢下去,這個 TransactionStatus 還是一個介面。 看看這個介面定義了哪些服務(方法):

hasSavepoint() ;
isCompleted() ;  
isNewTransaction() ;
setRollbackOnly() ;

當需要回滾的時候,需要在呼叫 setRoolbackOnly(); 就OK了。

好了,走了這麼久,現在就來簡單總結一下程式設計式事務管理。

首先: 因為我們使用的是特定的平臺,所以,我們需要建立一個合適我們的平臺事務管理PlateformTransactionManager。如果使用的是JDBC的話,就用DataSourceTransactionManager。注意需要傳入一個DataSource,這樣,平臺才知道如何和資料庫打交道。

第二: 為了使得平臺事務管理器對我們來說是透明的,就需要使用 TransactionTemplate。使用TransactionTemplat需要傳入一個 PlateformTransactionManager 進入,這樣,我們就得到了一個 TransactionTemplate,而不用關心到底使用的是什麼平臺了。

第三: TransactionTemplate 的重要方法就是 execute 方法,此方法就是呼叫 TransactionCallback 進行處理。

也就是說,實際上我們需要處理的事情全部都是在 TransactionCallback 中編碼的。

第四: 也就是 TransactionCallback 介面,我們可以定義一個類並實現此介面,然後作為 TransactionTemplate.execute 的引數。把需要完成的事情放到 doInTransaction中,並且傳入一個 TransactionStatus 引數。此引數是來呼叫回滾的。

也就是說 ,PlateformTransactionManager 和 TransactionTemplate 只需在程式中定義一次,而TransactionCallback 和 TransactionStatus 就要針對不同的任務多次定義了。

這就是Spring的程式設計式事務管理。下面貼出例子程式碼:

TemplateUtils

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

public class TemplateUtils {
	private static Logger logger = Logger.getLogger(TemplateUtils.class);
	private static String oracleDS = "java:OracleDS";
	private static DataSource dataSource = null;

	static {
		try {
			Context context = new InitialContext();
			dataSource = (DataSource) context.lookup(oracleDS);
		} catch (NamingException e) {
			logger.info("查詢資料來源失敗···", e);
		}
	}

	public static TransactionTemplate getTransactionTemplate() {
		PlatformTransactionManager txManager = new DataSourceTransactionManager(
				dataSource);
		return new TransactionTemplate(txManager);
	}

	public static JdbcTemplate getJdbcTemplate() {
		return new JdbcTemplate(dataSource);
	}

	public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
		return new NamedParameterJdbcTemplate(dataSource);
	}

	public static SimpleJdbcTemplate getSimpleJdbcTemplate() {
		return new SimpleJdbcTemplate(dataSource);
	}

}


Test
 

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

@SuppressWarnings("all")
public class Test {

	public void m1() throws Exception {
		TransactionTemplate transactionTemplate = TemplateUtils
				.getTransactionTemplate();
		Object object = transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				try {
					// 資料庫操作1
					// 資料庫操作2
				} catch (Exception e) {
					status.setRollbackOnly();
					e.printStackTrace();
				}
				return null;
			}
		});
	}

	public void m2() throws Exception {
		TransactionTemplate transactionTemplate = TemplateUtils
				.getTransactionTemplate();
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			protected void doInTransactionWithoutResult(TransactionStatus s) {
				try {
					// 資料庫操作1
					// 資料庫操作2
				} catch (Exception e) {
					s.setRollbackOnly();
					e.printStackTrace();
				}
			}
		});
	}

	public void m3() throws Exception {
		Context ctx = new InitialContext();
		DataSource ds = (DataSource) ctx.lookup("java:OracleDS");
		JdbcTemplate jt = new JdbcTemplate(ds);
		DefaultTransactionDefinition tf = new DefaultTransactionDefinition();
		PlatformTransactionManager tm = new DataSourceTransactionManager(ds);
		TransactionStatus ts = tm.getTransaction(tf);
		try {
			// 資料庫操作1
			// 資料庫操作2
			tm.commit(ts);
		} catch (Exception e) {
			tm.rollback(ts);
			e.printStackTrace();
		}
	}

}

JdbcUtils
 

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

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

public class JdbcUtils {
	private static Logger logger = Logger.getLogger(JdbcUtils.class);
	private static String oracleDS = "java:OracleDS";
	private static DataSource dataSource = null;

	static {
		try {
			Context context = new InitialContext();
			dataSource = (DataSource) context.lookup(oracleDS);
		} catch (NamingException e) {
			logger.info("查詢資料來源失敗···", e);
		}
	}

	public static Connection getConnection() {
		Connection conn = null;
		try {
			conn = dataSource.getConnection();
		} catch (SQLException e) {
			logger.info("獲取資料庫連線失敗···", e);
		}
		return conn;
	}

	public static void close(Connection conn) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				logger.info("釋放資料庫連線失敗···", e);
			}
		}
	}

	public static void close(CallableStatement cs) {
		if (cs != null) {
			try {
				cs.close();
			} catch (SQLException e) {
				logger.info("關閉CallableStatement失敗···", e);
			}
		}
	}

	public static void close(PreparedStatement ps) {
		if (ps != null) {
			try {
				ps.close();
			} catch (SQLException e) {
				logger.info("關閉PreparedStatement失敗···", e);
			}
		}
	}

	public static void close(ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				logger.info("關閉ResultSet失敗···", e);
			}
		}
	}

	public static void setAutoCommit(Connection conn, boolean autoCommit) {
		if (conn != null) {
			try {
				conn.setAutoCommit(autoCommit);
			} catch (SQLException e) {
				logger.info("設定事務提交方式失敗···", e);
			}
		}
	}

	public static void commit(Connection conn) {
		if (conn != null) {
			try {
				conn.commit();
			} catch (SQLException e) {
				logger.info("提交事務失敗···", e);
			}
		}
	}

	public static void rollback(Connection conn) {
		if (conn != null) {
			try {
				conn.rollback();
			} catch (SQLException e) {
				logger.info("回滾事務失敗···", e);
			}
		}
	}

	public static void rollback(Connection conn, Savepoint sp) {
		if (conn != null) {
			try {
				conn.rollback(sp);
			} catch (SQLException e) {
				logger.info("回滾事務失敗···", e);
			}
		}
	}

}

 

相關文章