Solon 的事務管理工具類(TranUtils)

带刺的坐椅發表於2024-04-14

Solon 在編碼上,是強調註解與手寫並重的一個風格。它有個 @Tran 註解,用於事務管理(可以參考:《事務的全域性控制及應用》)。這裡,主要是講講它的手動處理工具類 TranUtils

1、看看它的介面:

public final class TranUtils {
    //執行事務
    public static void execute(Tran tran, RunnableEx runnable) throws Throwable;
    //是否在事務中
    public static boolean inTrans();
    //是否在事務中且只讀
    public static boolean inTransAndReadOnly();
    //監聽事務
    public static void listen(TranListener listener) throws IllegalStateException;
    //獲取連結
    public static Connection getConnection(DataSource ds) throws SQLException;
    //獲取連結代理(方便,用於第三方框架事務對接)
    public static Connection getConnectionProxy(DataSource ds) throws SQLException;
}

2、那怎麼用它呢?

  • 用它判斷當前是否在事務中?
if(TranUtils.inTrans()){
    //正在事務中嘍...
}
  • 做一個手動的事務控制(與 @Tran 註解等同效果)
@Component
public class UserService{
    
    //@Tran(policy=TranPolicy.requires_new) 
    public void addUser(UserModel user)  throws Throwable{
        TranUtils.execute(new TranAnno().policy(TranPolicy.requires_new), ()->{
            //...
        });
    }
}

@Controller
public class DemoController{
    @Inject
    UserService userService; 
    
    //父回滾,子不回滾
    //
    //@Tran
    @Mapping("/user/add2")
    pubblic void addUser2(UserModel user){
        TranUtils.execute(new TranAnno(), ()->{
            userService.addUser(user); 
            throw new RuntimeException("不讓你加;但還是加了:(");
        });
    }
}
  • 用它與 dbvisitor (或者別的第三方框架)做事務託管對接
public class SolonManagedDynamicConnection implements DynamicConnection {
    private DataSource ds;

    public SolonManagedDynamicConnection(DataSource ds) {
        this.ds = ds;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return TranUtils.getConnectionProxy(ds);
    }

    @Override
    public void releaseConnection(Connection conn) throws SQLException {
        conn.close();
    }
}

3、TranUtils 是個麻雀工具

麻雀雖然,五臟具全。還可以在執行時,動態新增事務監聽哦。先看看事務監聽器介面:

public interface TranListener {
    //順序位
    default int getIndex();
    //提交之前(可以出異常觸發回滾)
    default void beforeCommit(boolean readOnly) throws Throwable;
    //完成之前
    default void beforeCompletion();
    //提交之後
    default void afterCommit();
    //完成之後
    default void afterCompletion(int status);
}

然後,我們試著做一個事務監聽:

@Component
public class UserService {
    @Inject
    UserDao userDao;
    
    //新增並使用事務
    @Tran
    public void addUserAndTran(User user){
        userDao.add(user);
        onUserAdd();
        
        //這裡明確知道有事務
        TranUtils.listen(new TranListener() {
            @Override
            public void afterCompletion(int status) {
                System.err.println("---afterCompletion: " + status);
            }
        });
    }
    
    //新增(不使用事務)
    public vod addUser(User user){
        userDao.add(user);
        onUserAdd();
    }
    
    private void onUserAdd(){
        //這裡不確定是否有事務,先判斷下
        if(TranUtils.inTrans()){
            TranUtils.listen(new TranListener() {
                @Override
                public void afterCompletion(int status) {
                    System.err.println("---afterCompletion: " + status);
                }
            });
        }
    }
}

相關文章