概述:
为了学习事务的管理,实现了如下的一个简单版本的事务管理器,进行实验。该管理器简化了事务管理的各种异常类型的考虑。
对于Transaction 管理
为了实现数据一致性,对于数据库的JDBC编程通常需要在代码中显示的调用Connection方法的事务相关API来完成工作。
常见的代码如下:
在以上的代码中与业务逻辑相关的代码只有一行, 为了简化事务的操作,实现一个简单的事务管理控制。主要提供以下方面的统一控制。
1.使用回调机制简化事务处理的代码
2.增加对事务隔离级别的支持
3.增加事务Timeout的管理,最简单的实现。 尽早发现长事务的操作。
4.对于savepoint的支持
5.实现一种事务传播控制。 如果当前存在事务,就加入该事务中执行,如果没有新建事务,放到事务中实现。
实现了该事务控制管理器后,将Service的代码得到如下的简化:
1. 回调的实现
定义模板类TransactionTemplate
其主要的方法就是提供模板方法对事务处理的代码进行控制:
2. 回调接口的定义非常的简单:
3. 重点Transaction类的实现,管理了Connection对象,事务隔离级别的定义,事务的savepoint控制点,以及对于事务状态的控制。
1) 对于savePoints属性记录了所有的事务的保存点,当service运行抛出Exception时,将进入rollback逻辑,这个时候,rollback方法会查找相应的Exception的保存点,将事务回滚到该保存点。
具体的保存点检查代码如下:
public void addSavepointAndRollbackException(String name, Exception e)
public boolean isSupportSavepoint() throws SQLException{}
private Savepoint addSavePoint(String savepointName) throws SQLException{}
public boolean containsSavepoint() {}
public Savepoint getSavePointByException(Exception e) {}
2) 属性newTrCount主要是用于实现事务的传播控制。当且仅当该值为1时候表示该事务是新创建的一个事务。当一个service运行的时候,如果发现当前的service线程已经有事务对象,那么这个时候就不需要再重新创建事务,只需要将原有的事务对象的计数器加1,那么相应的当该Serice运行完成才将事务减一,从而保证只有最外层的service看到的事务对象是新创建的事务对象,会执行真正的事务操作,而其他嵌套的Service对象,只是对该count进行操作。
提供了如下的三个方法方便控制:
public void addNewService(){
this.newTrCount++;
}
public void completeService(){
this.newTrCount--;
}
public boolean isNewTransaction(){
return this.newTrCount == 1;
}
4. 核心对象TransactionManager 该对象管理了Transaction对象,并且控制着事务的操作。
其代码如下
5. ConnectionManager对象的实现
为了学习事务的管理,实现了如下的一个简单版本的事务管理器,进行实验。该管理器简化了事务管理的各种异常类型的考虑。
对于Transaction 管理
为了实现数据一致性,对于数据库的JDBC编程通常需要在代码中显示的调用Connection方法的事务相关API来完成工作。
常见的代码如下:
public void doService(){
Connection connection = getConnection();
connection.setTransactionIsolation(
Connection.TRANSACTION_READ_COMMITTED);
try{
doBusinessLogic(connection);
connection.commit();
}catch(Exception e){
connection.rollback();
}finally{
connection.close();
}
}
在以上的代码中与业务逻辑相关的代码只有一行, 为了简化事务的操作,实现一个简单的事务管理控制。主要提供以下方面的统一控制。
1.使用回调机制简化事务处理的代码
2.增加对事务隔离级别的支持
3.增加事务Timeout的管理,最简单的实现。 尽早发现长事务的操作。
4.对于savepoint的支持
5.实现一种事务传播控制。 如果当前存在事务,就加入该事务中执行,如果没有新建事务,放到事务中实现。
实现了该事务控制管理器后,将Service的代码得到如下的简化:
private Service service;
private Dao dao;
private TransactionTemplate transactionTemplate;
public void service(final Object obj) {
this.trTemplate.executeTransaction(new TransactionCallback(){
public Object doTransactionEvent() {
service.doService();
transactionTemplate.addSavePoint("savepoint1", exception1);
dao.saveMethod1(obj);
transactionTemplate.addSavePoint("savepoint2", exception2);
dao.saveMethod2(obj);
}
});
}
1. 回调的实现
定义模板类TransactionTemplate
其主要的方法就是提供模板方法对事务处理的代码进行控制:
public class TransactionTemplate {
private TransactionManager trManager;
//the timeout monitor is used to find out all long time transaction in advance.
private boolean useTimeoutMonitor = Boolean.TRUE;
private Long maxTime = Long.valueOf(2);
public void addSavePoint(String savePointName, Exception rollbackException){
this.trManager.addSavePoint(savePointName, rollbackException);
}
public void executeTransaction(
TransactionCallback transactionCallback, int isolationLevel) {
long startTime = System.currentTimeMillis();
Transaction transaction = null;
try{
transaction = trManager.beginTransaction();
checkTimeout(startTime);
transaction.setTransactionIsolationLevel(isolationLevel);
transactionCallback.doTransactionEvent();
checkTimeout(startTime);
trManager.commitTransaction(transaction);
}catch(Exception e){
trManager.rollbackTransaction(transaction, e);
}finally{
trManager.closeTransaction(transaction);
}
}
/**
* If the transaction is timeout throw a transaction time out exception.
*/
private void checkTimeout(long startTime) {
if( this.useTimeoutMonitor ){
if(isTimeout(startTime)){
throw new TransactionTimeoutException();
}
}
}
private boolean isTimeout(long startTime) {
return System.currentTimeMillis() - startTime > this.maxTime ;
}
public void executeTransaction(TransactionCallback transactionCallback){
this.executeTransaction(transactionCallback, Transaction.DEFAULT_ISOLATION_LEVEL);
}
public Long getMaxTime() {
return maxTime;
}
public void setMaxTime(Long maxTime) {
this.maxTime = maxTime;
}
}
2. 回调接口的定义非常的简单:
public interface TransactionCallback {
public Object doTransactionEvent();
}
3. 重点Transaction类的实现,管理了Connection对象,事务隔离级别的定义,事务的savepoint控制点,以及对于事务状态的控制。
public class Transaction {
public static final int READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
public static final int READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
public static final int REPEATALB_READ = Connection.TRANSACTION_REPEATABLE_READ;
public static final int SERIALIZE = Connection.TRANSACTION_SERIALIZABLE;
public static final int DEFAULT_ISOLATION_LEVEL = READ_COMMITTED;
private Map<Exception,Savepoint> savePoints = new HashMap<Exception, Savepoint>();
//This count is used to implement the transaction propagation
private int newTrCount = 1;
Connection connection;
public Transaction(Connection connection){
this.connection = connection;
}
public void addNewService(){
this.newTrCount++;
}
public void completeService(){
this.newTrCount--;
}
public boolean isNewTransaction(){
return this.newTrCount == 1;
}
/**
* @return the connection
*/
public Connection getConnection() {
return connection;
}
/**
* @param connection the connection to set
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/**
* @param transactionIsolationLevel the transactionIsolationLevel to set
* @throws SQLException
*/
public void setTransactionIsolationLevel(int transactionIsolationLevel) throws SQLException {
this.connection.setAutoCommit(false);
this.connection.setTransactionIsolation(transactionIsolationLevel);
}
public void addSavepointAndRollbackException(String name, Exception e)
throws SQLException{
Savepoint savepoint = this.addSavePoint(name);
this.savePoints.put(e, savepoint);
}
public boolean isSupportSavepoint() throws SQLException{
return this.getConnection().getMetaData().supportsSavepoints();
}
private Savepoint addSavePoint(String savepointName) throws SQLException{
return this.connection.setSavepoint(savepointName);
}
public boolean containsSavepoint() {
return !this.savePoints.isEmpty();
}
public Savepoint getSavePointByException(Exception e) {
return this.savePoints.get(e);
}
}
1) 对于savePoints属性记录了所有的事务的保存点,当service运行抛出Exception时,将进入rollback逻辑,这个时候,rollback方法会查找相应的Exception的保存点,将事务回滚到该保存点。
具体的保存点检查代码如下:
public void addSavepointAndRollbackException(String name, Exception e)
public boolean isSupportSavepoint() throws SQLException{}
private Savepoint addSavePoint(String savepointName) throws SQLException{}
public boolean containsSavepoint() {}
public Savepoint getSavePointByException(Exception e) {}
2) 属性newTrCount主要是用于实现事务的传播控制。当且仅当该值为1时候表示该事务是新创建的一个事务。当一个service运行的时候,如果发现当前的service线程已经有事务对象,那么这个时候就不需要再重新创建事务,只需要将原有的事务对象的计数器加1,那么相应的当该Serice运行完成才将事务减一,从而保证只有最外层的service看到的事务对象是新创建的事务对象,会执行真正的事务操作,而其他嵌套的Service对象,只是对该count进行操作。
提供了如下的三个方法方便控制:
public void addNewService(){
this.newTrCount++;
}
public void completeService(){
this.newTrCount--;
}
public boolean isNewTransaction(){
return this.newTrCount == 1;
}
4. 核心对象TransactionManager 该对象管理了Transaction对象,并且控制着事务的操作。
其代码如下
public class TransactionManager {
private ConnectionManager connectionManager;
private ThreadLocal<Transaction> transactions = new ThreadLocal<Transaction>();
public Transaction beginTransaction() {
try{
Transaction tr = this.transactions.get();
if( tr == null ){
Connection connection = connectionManager.getConnection();
connectionManager.setTransactionActive(true);
tr = new Transaction(connection);
this.transactions.set(tr);
}else{
tr.addNewService();
}
return tr;
}catch(Exception e){
throw new TransactionException();
}
}
public void commitTransaction(Transaction transaction) {
try{
if( transaction.isNewTransaction() ){
connectionManager.setTransactionActive(false);
connectionManager.commit(transaction.getConnection());
}
}catch(Exception e){
throw new TransactionException();
}
}
public void rollbackTransaction(Transaction transaction, Exception e) {
try{
if( transaction.isNewTransaction() ){
connectionManager.setTransactionActive(false);
if(transaction.containsSavepoint()){
Savepoint savepoint = transaction.getSavePointByException(e);
if( savepoint == null ){
connectionManager.rollback(transaction.getConnection());
}else{
connectionManager.rollback(transaction.getConnection(), savepoint);
}
}else{
connectionManager.rollback(transaction.getConnection());
}
}
}catch( Exception e2){
throw new TransactionException();
}
}
public void closeTransaction(Transaction transaction){
try{
if( transaction.isNewTransaction() ){
this.transactions.remove();
connectionManager.setTransactionActive(false);
connectionManager.releaseConnection(transaction.getConnection());
}else{
transaction.completeService();
}
}catch(Exception e){
throw new TransactionException();
}
}
/**
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
/**
* @return the connectionManager
*/
public ConnectionManager getConnectionManager() {
return connectionManager;
}
/**
* @param connectionManager the connectionManager to set
*/
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
public void addSavePoint(String savePointName, Exception rollbackException){
Transaction tr = this.transactions.get();
if(tr == null){
tr = this.beginTransaction();
}
try{
if(!tr.isSupportSavepoint()){
throw new SavePointNotSupportException();
}
tr.addSavepointAndRollbackException(savePointName, rollbackException);
}catch(Exception e){
throw new TransactionException();
}
}
}
5. ConnectionManager对象的实现
public class ConnectionManager {
private static ConnectionManager connectionManager = new ConnectionManager();
ThreadLocal<Connection> threadConnection = new ThreadLocal<Connection>();
private ConnectionManager(){}
public static ConnectionManager getConnectionManager(){
return connectionManager;
}
private Boolean isTransactionActive = Boolean.FALSE;
public Connection getConnection() throws ClassNotFoundException, SQLException{
Connection connection = this.threadConnection.get();
if( connection == null ){
connection = (Connection) DriverManager.getConnection (
"jdbc:sqlserver://10.171.30.11:1433;instanceName=nasa;databaseName=nasa2_SMS_PT;SelectMethod=cursor;characterEncoding=utf-8;autoReconnectForPools=true;autoReconnect=true",
"sms", "sms");
this.threadConnection.set(connection);
}
return connection;
}
public void releaseConnection(Connection connection) throws SQLException{
if( !isTransactionActive ){
threadConnection.remove();
connection.close();
}
}
public void commit(Connection connection) throws SQLException{
if( !isTransactionActive ){
connection.commit();
}
}
public void rollback(Connection connection) throws SQLException{
if( !isTransactionActive ){
connection.rollback();
}
}
public void rollback(Connection connection, Savepoint savepoint) throws SQLException{
if( !isTransactionActive ){
connection.rollback(savepoint);
}
}
/**
* @param isTransactionFinished the isTransactionFinished to set
*/
public void setTransactionActive(Boolean isTransactionActive) {
this.isTransactionActive = isTransactionActive;
}
}