JFinal使用事务及其原理

本文详细介绍了JFinal中声明式事务的使用,包括如何通过注解配置事务,事务的实现原理,如建立数据库连接、设置事务隔离级别、事务提交和回滚。此外,还讨论了事务隔离级别的配置,并提及了JFinal提供的不同隔离级别拦截器。最后,提到了一种不依赖拦截器的事务实现方式,通过DbPro.java进行事务管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用声明式事务

事务类本身就是一个拦截器,可以用注解的方式配置。方法内部的所有 DML 操作都将在本次事务之内。

配置代码如下:

@Before(Tx.class)
public void savePost(){
    //...
}

事务配置就是这么简单任性。

 

声明式事务实现原理

上述配置中为 savePost() 配置了事务也就是拦截器 Tx,当调用到 savePost() 的时候,是会进入到 Tx 的 intercept 方法中的:

  1. 建立数据库连接;
  2. 设置事务隔离级别;
  3. 设置事务手动提交;
  4. 反射机制调用 savePost();
  5. 事务提交;
  6. 若事务失败,就回滚。

主要代码如下:

public void intercept(Invocation inv) {
    Config config = getConfigWithTxConfig(inv);
    if (config == null)
        config = DbKit.getConfig();
    
    Connection conn = config.getThreadLocalConnection();
    // 下面这段支持嵌套事务,可以忽略不看
    if (conn != null) {
        try {
            if (conn.getTransactionIsolation() < getTransactionLevel(config))
                conn.setTransactionIsolation(getTransactionLevel(config));
            inv.invoke();
            return ;
        } catch (SQLException e) {
            throw new ActiveRecordException(e);
        }
    }
    
    Boolean autoCommit = null;
    try {
        // 1. 建立数据库连接
        conn = config.getConnection();
        autoCommit = conn.getAutoCommit();
        config.setThreadLocalConnection(conn);
        // 2. 设置事务隔离级别
        conn.setTransactionIsolation(getTransactionLevel(config));    // conn.setTransactionIsolation(transactionLevel);
        // 3. 设置事务手动提交
        conn.setAutoCommit(false);
        // 4. 反射机制调用 savePost()
        inv.invoke();
        // 5. 事务提交
        conn.commit();
    } catch (NestedTransactionHelpException e) {
        if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
        LogKit.logNothing(e);
    } catch (Throwable t) {
        // 6. 若有异常就回滚
        if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
        throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
    }
    finally {
        try {
            if (conn != null) {
                if (autoCommit != null)
                    conn.setAutoCommit(autoCommit);
                conn.close();
            }
        } catch (Throwable t) {
            LogKit.error(t.getMessage(), t);    // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
        }
        finally {
            config.removeThreadLocalConnection();    // prevent memory leak
        }
    }
}

 

事务隔离级别

Tx.java 使用的是 JFinal 默认配置的事务隔离级别,是在 DbKit.java 中配置的

public static final int DEFAULT_TRANSACTION_LEVEL = Connection.TRANSACTION_REPEATABLE_READ;

 

JFinal 还有几个拦截器,可以根据事务隔离级别的需求选用。

它们都继承与 Tx.java,唯一不同的就是事务隔离级别。

以 TxReadCommitted 为例。

继承 Tx.java,覆盖了 getTransactionLevel 方法,返回常量值,这个常量就代表了事务隔离级别。

public class TxReadCommitted extends Tx {
    
    /**
     * A constant indicating that
     * dirty reads are prevented; non-repeatable reads and phantom
     * reads can occur.  This level only prohibits a transaction
     * from reading a row with uncommitted changes in it.
     */
    private int TRANSACTION_READ_COMMITTED   = 2;
    
    @Override
    protected int getTransactionLevel(com.jfinal.plugin.activerecord.Config config) {
        return TRANSACTION_READ_COMMITTED;
    }
}

 

另一种实现事务的方式

这种实现方式并没有使用拦截器。

跟踪代码最终追到 DbPro.java 如下代码中:

boolean tx(Config config, int transactionLevel, IAtom atom) {
    Connection conn = config.getThreadLocalConnection();
    if (conn != null) {    // Nested transaction support
        try {
            if (conn.getTransactionIsolation() < transactionLevel)
                conn.setTransactionIsolation(transactionLevel);
            boolean result = atom.run();
            if (result)
                return true;
            throw new NestedTransactionHelpException("Notice the outer transaction that the nested transaction return false");    // important:can not return false
        }
        catch (SQLException e) {
            throw new ActiveRecordException(e);
        }
    }
    
    Boolean autoCommit = null;
    try {
        // 1. 建立数据库连接
        conn = config.getConnection();
        autoCommit = conn.getAutoCommit();
        config.setThreadLocalConnection(conn);
        // 2. 设置事务隔离级别
        conn.setTransactionIsolation(transactionLevel);
        // 3. 设置事务手动提交
        conn.setAutoCommit(false);
        // 4. 所有 DML 操作是否都执行成功?
        boolean result = atom.run();
        // 5. 都成功:提交;不是都成功:回滚
        if (result)
            conn.commit();
        else
            conn.rollback();
        return result;
    } catch (NestedTransactionHelpException e) {
        if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
        LogKit.logNothing(e);
        return false;
    } catch (Throwable t) {
        if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
        throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
    } finally {
        try {
            if (conn != null) {
                if (autoCommit != null)
                    conn.setAutoCommit(autoCommit);
                conn.close();
            }
        } catch (Throwable t) {
            LogKit.error(t.getMessage(), t);    // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
        } finally {
            config.removeThreadLocalConnection();    // prevent memory leak
        }
    }
}

主要事务流程:

  1. 建立数据库连接;
  2. 设置事务隔离级别;
  3. 设置事务手动提交;
  4. 调用 Atom 的 run 方法,所有 DML 操作是否都执行成功? 若都成功则事务提交,反之事务回滚。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值