亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

spring聲明式事務@Transactional開發(fā)常犯的幾個錯誤及最新解決方案

 更新時間:2024年02月04日 09:37:55   作者:夢在旅途  
使用聲明式事務@Transactional進行事務一致性的管理,在開發(fā)過程中,發(fā)現(xiàn)很多開發(fā)同學都用錯了spring聲明式事務@Transactional或使用不規(guī)范,導致出現(xiàn)各種事務問題,這篇文章主要介紹了spring聲明式事務@Transactional開發(fā)常犯的幾個錯誤及解決辦法,需要的朋友可以參考下

目前JAVA的微服務項目基本都是SSM結(jié)構(gòu)(即:springCloud +springMVC+Mybatis),而其中Mybatis事務的管理也是交由spring來管理,大部份都是使用聲明式事務(@Transactional)來進行事務一致性的管理,然后在實際日常開發(fā)過程中,發(fā)現(xiàn)很多開發(fā)同學都用錯了spring聲明式事務(@Transactional)或者說使用非常不規(guī)范,導致出現(xiàn)各種事務問題。我(夢在旅途)今天周日休息,花了幾個小時把目前我已知的開發(fā)常犯的幾個錯誤都列舉出來并逐一分析根本原因同時針對原因給出解決方案及示例,希望能幫助到廣大JAVA開發(fā)者。

1. 事務不生效

問題現(xiàn)象:明明有事務注解,在事務方法內(nèi)部有拋錯,但事務卻沒有回滾,該執(zhí)行的SQL都執(zhí)行了

示例代碼如下:(doInsert方法是有事務注解的)

/**
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Service
public class DemoUserService {
    //... ...
   public DemoUser doGet() {
        try {
            doInsert(1);
        } catch (Exception ex) {
            System.out.println("insert error: " + ex.toString());
        }
        return demoUserMapper.get(1);
    }
        @Transactional
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        throw new RuntimeException("mock insert ex");  //模擬拋錯
 		return result;
    }
}
//演示調(diào)用,最終打印出了ID為1的那條記錄,事務并沒有回滾
DemoUser result = demoUserService.doGet();
System.out.println(result != null ? result.toString() : "none");
  • 根本原因:沒有執(zhí)行事務AOP切面,因為在BEAN方法內(nèi)部直接調(diào)用另一個公開的事務方法,是原生的方法之間調(diào)用,并非是被代理后的BEAN方法,所以SPRING事務注解在這種情況下失去作用。

解決方案:不論是在BEAN外部或BEAN方法內(nèi)部,要確保一定是調(diào)用代理BEAN的公開事務方法,確保調(diào)用事務方法有被SPRING事務攔截處理,示例代碼如下:【在BEAN內(nèi)部則需要先注入BEAN本身的代理BEAN實例(有很多中獲取當前BEAN的代理BEAN方案,在此不細說),然后通過代理BEAN調(diào)事務方法即可。】

/**
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Service
public class DemoUserService {
    @Autowired
    @Lazy //加上這個,是防止循環(huán)自依賴
    private DemoUserService selfService; //注入自己的代理BEAN實例
        //... ...
    public DemoUser doGet() {
        try {
           selfService.doInsert(1); //這里改為使用代理BEAN調(diào)doInsert的事務方法,確保走切面
        } catch (Exception ex) {
            System.out.println("insert error: " + ex.toString());
        }
        return demoUserMapper.get(1);
    }
    @Transactional
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        throw new RuntimeException("mock insert ex");
//        return result;
    }
}
//演示調(diào)用,最終打印出了none,說明事務有回滾,無法查出ID為1的那個記錄
DemoUser result = demoUserService.doGet();
System.out.println(result != null ? result.toString() : "none");

2. 事務提交報錯

問題現(xiàn)象:事務方法內(nèi)有catch住錯誤,但卻無法正常提交事務,報錯:Transaction rolled back because it has been marked as rollback-only,示例代碼如下:

/**
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Service
public class DemoUserService {
    @Autowired
    @Lazy //加上這個,是防止循環(huán)自依賴
    private DemoUserService selfService; //注入自己的代理BEAN實例
        //... ...
    @Transactional
    public DemoUser doGet() {
        try {
           selfService.doInsert(1);
        } catch (Exception ex) { //有catch錯誤,但當doGet返回時卻報錯了
            System.out.println("insert error: " + ex.toString());
        }
        return demoUserMapper.get(1);
    }
    @Transactional
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==1) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }
}
//演示調(diào)用,最終有報錯:Transaction rolled back because it has been marked as rollback-only
DemoUser result = demoUserService.doGet();
System.out.println(result != null ? result.toString() : "none");
  • 根本原因:事務繼承“惹的禍”【事務傳播特性】,入口事務方法內(nèi)部再調(diào)其他事務方法,其他事務方法若有拋錯則會在方法返回時被事務切面標記當前事務僅能回滾,若最后入口事務方法執(zhí)行完成并想提交事務時卻因為事務是繼承的且有被標記為僅能回滾后則只能報錯

解決方案:避免事務繼承 或 確保事務方法內(nèi)部不再調(diào)用其他事務方法(即:事務方法變成普通方法,小技巧參照我之前文章:任何Bean通過實現(xiàn)ProxyableBeanAccessor接口即可獲得動態(tài)靈活的獲取代理對象或原生對象的能力 - 夢在旅途 - 博客園 (cnblogs.com)),示例代碼如下:

/**
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Service
public class DemoUserService {
    @Autowired
    @Lazy //加上這個,是防止循環(huán)自依賴
    private DemoUserService selfService; //注入自己的代理BEAN實例
        //... ...
    @Transactional
    public DemoUser doGet() {
        try {
           selfService.doInsert(1);
           // doInsert(1);  方案二:內(nèi)部直接doInsert方法,此時是原生方法調(diào)用,不走事務切面,也就不會觸發(fā)事務記錄的情況
        } catch (Exception ex) { //有catch錯誤
            System.out.println("insert error: " + ex.toString());
        }
        selfService.doInsert(2);
        return demoUserMapper.get(2);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW) //方案一:這里加上REQUIRES_NEW、或NOT_SUPPORTED,確保不繼承外部事務即可
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==1) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }
}
//演示調(diào)用,最終正確打印了ID為2的記錄,說明雖然插入ID=1的記錄失敗了,但插入2的記錄是正確的,入口事務有正確的提交
DemoUser result = demoUserService.doGet();
System.out.println(result != null ? result.toString() : "none");

3. 事務不回滾

問題現(xiàn)象:事務方法內(nèi)部有報錯,但事務卻仍提交了,示例代碼如下:

  /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
//第一種情況:錯誤被catch住了
@Transactional
    public DemoUser doGet1() {
        try {
            doInsert(1); //doInsert原生調(diào)用,代碼看似有事務,實際此時無事務,也就不存在事務回滾的情況
        } catch (Exception ex) { //catch錯誤,doGet事務正常提交
            System.out.println("insert error: " + ex.toString());
        }
        selfService.doInsert(2);
        return demoUserMapper.get(2);
    }
//第二種情況:外層報錯,內(nèi)層事務正常提交
	@Transactional
    public DemoUser doGet2() {
        selfService.doInsert(2); //doInsert切面調(diào)用,有事務且單獨事務,執(zhí)行完即提交
        throw new RuntimeException("mock doGet ex");//這里拋錯不影響doInsert的提交
        return demoUserMapper.get(2);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==1) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }
//演示調(diào)用,第1種情況
DemoUser result = demoUserService.doGet1();
System.out.println(result != null ? result.toString() : "none");
//演示調(diào)用,第2種情況
DemoUser result = demoUserService.doGet2();
System.out.println(result != null ? result.toString() : "none");
  • 根本原因:一是錯誤被catch住了,這種情況下事務切面認為是正常的則會正常執(zhí)行提交事務,二是根本就沒有事務或事務并非同一個事務(與事務傳播特性有關(guān)),這種情況就好理解,沒事務就不存在事務提交(方法中的每個SQL即為一個小事務,執(zhí)行即提交),若是事務方法內(nèi)部有嵌套調(diào)用其他事務方法,入口的外層事務會受內(nèi)部其他事務方法的影響,反之若其他事務方法與外層事務不是同一個事務,那么外層事務有報錯并不會影響內(nèi)部其他事務方法

    • 這里還補充一種特殊情況,若在事務方法中異步調(diào)用其他事務方法(@Async 或線程池直接調(diào)用等情況),那么由于不在同一個線程上下文,即使默認是繼承的傳播特性也無變成2個不相干的事務各自執(zhí)行,異步事務方法的報錯不會影響外層的事務方法

解決方案:若需保證事務的完整性,需確保若有異常一定要拋錯而非catch錯誤,另外需確保一定有事務,當事務方法內(nèi)部有嵌套調(diào)用其他事務方法時,若希望被調(diào)用的事務方法與當前事務保持一致,那么就應確保是事務繼承,否則就說明可以允許局部事務不一致,示例代碼如下:

 /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Transactional
    public DemoUser doGet() {
        doInsert(1);//不要catch,若catch后記錄日志后再拋出,總之一定要拋錯
        selfService.doInsert(1);//這種也可以,當doInsert報錯,則doInsert與doGet方法均回滾(本質(zhì)是同一個事務)
        selfService.doInsert(2);
        return demoUserMapper.get(2);
    }
    @Transactional(propagation = Propagation.REQUIRED) //若需與外層事務這一致,這里建議采用REQUIRED的傳播特性
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==1) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }

4. 死鎖

問題現(xiàn)象:執(zhí)行SQL有報死鎖,示例代碼如下:

  /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Transactional
    public DemoUser doGetX() {
        selfService.doInsert(1);
        DemoUser user=selfService.get(1);
        user.setName("xxx");
        update(user); //這里是原生方法調(diào)用,等同于在doGetX同一個事務方法內(nèi)部執(zhí)行
        user.setName("xxx2");
        selfService.update(user); //這里新開事務調(diào)用,由于doGetX中已經(jīng)有調(diào)用update(id=1)且事務還未提交,故這里需要等待doGetX事務提交以便釋放鎖,而doGetX事務則因為這里等待無法往下執(zhí)行,形成事務循環(huán)自依賴了
        return demoUserMapper.get(1);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW) //這里新開事務
    public int update(DemoUser demoUser) {
        return demoUserMapper.update(demoUser);
    }
//演示調(diào)用,執(zhí)行報錯,不同DB的報錯提示可能有所不同
DemoUser result = demoUserService.doGetX();
System.out.println(result != null ? result.toString() : "none");    
  • 根本原因:事務被循環(huán)自依賴了,再準確的說就是同一個記錄被2個事務相互依賴,導致相互等待獲取鎖

解決方案:避免事務被循環(huán)自依賴,示列代碼如下:

 /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
//優(yōu)化一
    @Transactional
    public DemoUser doGetX() {
        selfService.doInsert(1);
        DemoUser user=selfService.get(1);
        user.setName("xxx");
        update(user); //這里是原生方法調(diào)用,等同于在doGetX同一個事務方法內(nèi)部執(zhí)行
        user.setName("xxx2");
        update(user); //這里也改為原生方法調(diào)用,等同于在doGetX同一個事務方法內(nèi)部執(zhí)行
        return demoUserMapper.get(1);
    }
     //優(yōu)化二
    @Transactional
    public DemoUser doGetX() {
        selfService.doInsert(1);
        DemoUser user=selfService.get(1);
        user.setName("xxx");
        selfService.update(user); //這里是代理BEAN方法調(diào)用,新開事務,直接執(zhí)行并提交,與doGetX事務互不影響
        user.setName("xxx2");
        selfService.update(user); //這里是代理BEAN方法調(diào)用,新開事務,直接執(zhí)行并提交,與doGetX事務互不影響
        return demoUserMapper.get(1);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW) //這里新開事務
    public int update(DemoUser demoUser) {
        return demoUserMapper.update(demoUser);
    }
//演示調(diào)用,執(zhí)行報錯,不同DB的報錯提示可能有所不同
DemoUser result = demoUserService.doGetX();
System.out.println(result != null ? result.toString() : "none");    

5. 在事務提交后回調(diào)事件方法中開事務不生效

問題現(xiàn)象:在事務提交后回調(diào)事件方法中【即:afterCommit】開啟事務不生效(即:添加了@Transactional,也執(zhí)行了代理方法的調(diào)用,但就像沒有事務一樣,出現(xiàn)報錯事務不回滾,也無法在事務方法中再次注冊事務提交后回調(diào)事務件方法),示例代碼如下:

 /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Transactional
    public DemoUser doGetX() {
        doInsert(1);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                selfService.doInsert(2);//走切面調(diào)用,確保執(zhí)行代理的事務方法,但實際還是無事務,報錯也不會回滾
            }
        });
        return demoUserMapper.get(1);
    }
    @Transactional(propagation = Propagation.REQUIRED)
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==2) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }
    //演示調(diào)用:雖然doGetX有報錯,但最終doInsert方法均有執(zhí)行,且都能查出ID=1 與2的記錄
        try {
            DemoUser result = demoUserService.doGetX();
            System.out.println(result != null ? result.toString() : "none");
        }catch (Exception e){
            System.out.println("error " + e.toString());
        }
        DemoUser result1 =demoUserService.get(1);
        System.out.println(result1 != null ? result1.toString() : "none");
        DemoUser result2 =demoUserService.get(2);
        System.out.println(result2 != null ? result2.toString() : "none");
  • 根本原因:在事務提交后回調(diào)事件方法中【即:afterCommit】,spring事務的管理狀態(tài)仍保留(即:仍是事務激活狀態(tài))但DB事務其實已提交,當回調(diào)方法中又遇到有事務注解的方法時且判斷已有事務(即spring事務的管理狀態(tài)是激活狀態(tài)transactionActive=true)時,若是默認繼承狀態(tài)則不會再開啟新事務,僅復用DB連接

解決方案:在事務提交后回調(diào)事件方法中【即:afterCommit】開啟新事務(即:傳播特性為:REQUIRES_NEW) 或者 執(zhí)行前強制清除事務狀態(tài)【需要編寫事務狀態(tài)清除工具類】,示例代碼如下:

 /**代碼片段
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
@Transactional
    public DemoUser doGetX() {
	    TxManagerUtils.clearTxStatus();//方案二:通過事務狀態(tài)清除工具類注冊事務回調(diào)后首先清除事務狀態(tài),二選其一即可
        doInsert(1);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                selfService.doInsert(2);//走切面調(diào)用,確保執(zhí)行代理的事務方法
            }
        });
        return demoUserMapper.get(1);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW) //方案一:這里強制開啟新事務,二選其一即可
    public int doInsert(int id) {
        DemoUser user = new DemoUser(id, "zs", 18, new BigDecimal("8888.88"),
                "shenzhen,cn", new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis()));
        int result = demoUserMapper.insert(user);
        if (id==2) {
            throw new RuntimeException("mock insert ex");
        }
        return result;
    }
    //演示調(diào)用:雖然doGetX有報錯,但只能查出ID=1的記錄,ID=2由于報錯事務回滾了,說明afterCommit中再開啟事務是OK的
        try {
            DemoUser result = demoUserService.doGetX();
            System.out.println(result != null ? result.toString() : "none");
        }catch (Exception e){
            System.out.println("error " + e.toString());
        }
        DemoUser result1 =demoUserService.get(1);
        System.out.println(result1 != null ? result1.toString() : "none");
        DemoUser result2 =demoUserService.get(2);
        System.out.println(result2 != null ? result2.toString() : "none");

事務狀態(tài)清除工具類如下:

package org.springframework.jdbc.datasource; //必需放在這個包目錄下,因為connectionHolder.setTransactionActive 是protected方法
import com.example.springwebapp.utils.SpringUtils;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.sql.DataSource;
/**
 * @author zuowenjun
 * @see wwww.zuowenjun.cn
 */
public class TxManagerUtils {
    //建議在每個事務方法的第一行調(diào)用,避免事務方法內(nèi)部中途若有其他方法需要注冊事務提交后回調(diào)方法
    public static void clearTxStatus() {
        DataSource dataSource = SpringUtils.getBean(DataSource.class);
        ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public int getOrder() {
                return Integer.MIN_VALUE; //確保最先執(zhí)行
            }
            @Override
            public void afterCommit() {
                doClearTxStatus(); //第一個回調(diào)事件中先清除事務狀態(tài)
            }
            @Override
            public void afterCompletion(int status) {
                TransactionSynchronizationManager.bindResource(dataSource, connectionHolder); //恢復DB連接綁定,避免執(zhí)行事務清理時報錯
            }
        });
    }
    private static void doClearTxStatus() {
        DataSource dataSource = SpringUtils.getBean(DataSource.class);
        TransactionSynchronizationManager.setActualTransactionActive(false); //設置事務狀態(tài)為非激活
        ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        connectionHolder.setTransactionActive(false);//設置事務狀態(tài)為非激活
        TransactionSynchronizationManager.unbindResource(dataSource); //暫時解綁DB連接
    }
}

注:后面我預計還會針對spring事務這塊進行其他方面的分享(比如:spring事務在多數(shù)據(jù)源中切換數(shù)據(jù)源不生效、事務隔離級別下的并發(fā)處理等),敬請期待,原創(chuàng)不易,若有不足歡迎指出,謝謝!

到此這篇關(guān)于spring聲明式事務@Transactional開發(fā)常犯的幾個錯誤及解決辦法的文章就介紹到這了,更多相關(guān)spring聲明式事務內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot使用Jasypt對配置文件和數(shù)據(jù)庫密碼加密

    SpringBoot使用Jasypt對配置文件和數(shù)據(jù)庫密碼加密

    在做數(shù)據(jù)庫敏感信息保護時,應加密存儲,本文就來介紹一下SpringBoot使用Jasypt對配置文件和數(shù)據(jù)庫密碼加密,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • Java Swing實現(xiàn)窗體添加背景圖片的2種方法詳解

    Java Swing實現(xiàn)窗體添加背景圖片的2種方法詳解

    這篇文章主要介紹了Java Swing實現(xiàn)窗體添加背景圖片的2種方法,結(jié)合實例形式較為詳細的分析了Swing實現(xiàn)窗體添加背景圖片的方法,并總結(jié)分析了Swing重繪中repaint與updateUI的區(qū)別,需要的朋友可以參考下
    2017-11-11
  • Java實現(xiàn)獲取銀行卡所屬銀行,驗證銀行卡號是否正確的方法詳解

    Java實現(xiàn)獲取銀行卡所屬銀行,驗證銀行卡號是否正確的方法詳解

    這篇文章主要介紹了Java實現(xiàn)獲取銀行卡所屬銀行,驗證銀行卡號是否正確的方法,結(jié)合實例形式詳細分析了java判斷銀行卡歸屬地及有效性的原理與相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-09-09
  • Java Swing SpringLayout彈性布局的實現(xiàn)代碼

    Java Swing SpringLayout彈性布局的實現(xiàn)代碼

    這篇文章主要介紹了Java Swing SpringLayout彈性布局的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Java?工具類實現(xiàn)音頻音量提升

    Java?工具類實現(xiàn)音頻音量提升

    本文主要介紹了可以將音頻提升音量的一個java工具類示例代碼,代碼具有一定的學習價值,感興趣的小伙伴來了解一下吧,,希望能夠給你帶來幫助
    2021-11-11
  • Java實現(xiàn)最小生成樹MST的兩種解法

    Java實現(xiàn)最小生成樹MST的兩種解法

    最小生成樹(MST)指在連通圖的所有生成樹中,所有邊的權(quán)值和最小的生成樹。本文介紹了求最小生成樹的兩種方法:Prim算法和Kruskal算法,需要的可以參考一下
    2022-05-05
  • Spring MVC項目中l(wèi)og4J和AOP使用詳解

    Spring MVC項目中l(wèi)og4J和AOP使用詳解

    項目日志記錄是項目開發(fā)、運營必不可少的內(nèi)容,有了它可以對系統(tǒng)有整體的把控,出現(xiàn)任何問題都有蹤跡可尋。下面這篇文章主要給大家介紹了關(guān)于Spring MVC項目中l(wèi)og4J和AOP使用的相關(guān)資料,需要的朋友可以參考下。
    2017-12-12
  • 編寫android撥打電話apk應用實例代碼

    編寫android撥打電話apk應用實例代碼

    這篇文章主要介紹了編寫android撥打電話apk應用實例代碼,十分的實用,這里分享給大家,有需要的小伙伴可以參考下
    2015-04-04
  • 常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實現(xiàn)示例

    常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實現(xiàn)示例

    這篇文章主要介紹了常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實現(xiàn)示例,一般來說DSA算法用于簽名的效率會比RSA要快,需要的朋友可以參考下
    2016-04-04
  • Spring詳細講解事務失效的場景

    Spring詳細講解事務失效的場景

    實際項目開發(fā)中,如果涉及到多張表操作時,為了保證業(yè)務數(shù)據(jù)的一致性,大家一般都會采用事務機制,好多小伙伴可能只是簡單了解一下,遇到事務失效的情況,便會無從下手,下面這篇文章主要給大家介紹了關(guān)于Spring事務失效場景的相關(guān)資料,需要的朋友可以參考下
    2022-07-07

最新評論