javascript
spring和spring_Spring交易可见性
spring和spring
在初始化應用程序上下文時,Spring在遇到帶有@Transactional標記的類時會創建代理。 @Transactional可以應用于類級別或方法級別。 在類級別應用它意味著該類中定義的所有公共方法都是事務性的。 Spring創建的代理類型,即Jdk代理或CGLIB代理,取決于將方法標記為事務性的類。 如果該類實現了至少一個接口,則Spring將創建一個Jdk動態代理。 該代理實現與原始類相同的接口,并使用事務維護邏輯攔截接口方法。 它將調用委托給其中組成的原始對象。 假設該類未實現任何接口,Spring將創建一個CGLIB代理。 該代理擴展了原始類并覆蓋了公共方法。 我們將盡快對此進行仔細研究。 假設我們有一個這樣定義的類:
public interface BookDao{void buyBook(String isbn) throws BookNotFoundException;Book findByIsbn(String isbn);int deductStock(Book book); }public class JdbcBookDao implements BookDao{void buyBook(String isbn) throws BookNotFoundException{Book book = findByIsbn(isbn);if(book == null){throw new BookNotFoundException();}deductStock(book);}@Transactional(propagation=Propagation.REQUIRES_NEW)Book findByIsbn(String isbn){Book book = getJdbcTemplate().queryForObject("SELECT * FROM BOOK WHERE ISBN=?",ParameterizedBeanPropertyRowMapper.newInstance(Book.class), isbn);return book;}@Transactional(propagation=Propagation.REQUIRES_NEW)int deductStock(Book book){String sql = "UPDATE BOOK_STOCK SET STOCK=STOCK-1 WHERE BOOK_ID=?";return getJdbcTemplate().update(sql, stockIncrement, book.getId());} }現在,Spring是否會通過從main方法調用bookDao的findByIsbn自動創建交易? 否。我們必須在xml配置中聲明這一點:
<tx:annotation-driven>因此,如果它不創建事務,是否會引發錯誤? 答案還是不是。Spring非事務地執行此語句。
正如我們所期望的那樣,一旦聲明了?tx:annotation-driven?,Spring將在該類實現接口時為JdbcBookDao創建一個Jdk動態代理。 現在說,我們調用JdbcBookDao的buyBook方法,Spring創建了多少個事務?
答案是(3)。 交易的默認交易模式為“代理”。 這意味著Spring僅考慮通過代理進行的方法調用進行自動事務管理。 現在,如果您仔細觀察,buyBook方法不會標記為事務性的。 因此,當創建事務代理時,該方法不會被事務管理邏輯攔截,因為它未標記為@Transactional。 簡而言之,buyBook不會在代理中被覆蓋。 因此,該方法直接在原始對象上調用。 因此,其他兩個方法也將在原始對象上調用。 請記住,只有PROXY包含事務管理代碼。 因此,當其他方法也被原始對象調用時,Spring根本不會創建事務。 現在,如果我們將buyBook標記為@Transactional,是否可以解決問題? Spring是否會為每個findByIsbn和deductStock方法創建兩個單獨的事務?
不會。調用buyBook()時,Spring僅創建一個事務。 由于不會在原始對象本身而不是代理上調用各個方法,因此不會進一步創建任何新事務。 那么如何解決這個問題呢?
我們可以要求Spring創建一個CGLIB proxy()嗎? 現在,由于代理是具有重寫的公共事務方法的子類,因此它為每個方法調用創建一個新事務? 再次沒有。 CGLIB代理不會直接在超類上調用該方法。 這是如何實現的粗略想法。
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;public class MyInterceptor implements MethodInterceptor {private Object realObject;public MyInterceptor(Object original) {this.realObject = original;}// This method will be called every time the object proxy calls any of its methodspublic Object intercept(Object o, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {/*** Transaction Management Code*/// Invoke the method on the real object with the given paramsObject res = method.invoke(realObject, args);/*** Transaction Management Code*/return res;} }import net.sf.cglib.proxy.Enhancer;public class ProxyCreator(){public static T createProxy(T original){// Enhancer is CGLIB class which builds a dynamic proxy with new capabilitiesEnhancer e = new Enhancer();e.setSuperclass(original.getClass());// We have to declare the interceptor whose 'intercept' will be called when methods are called on proxy.e.setCallback(new MyInterceptor(original));T proxy = (T) e.create();return proxy;} }因此,正如您在此處看到的,代理擴展了原始類并由其對象組成。 因此,當我們調用buyBook時,代理會創建一個事務并將該調用委托給原始對象。 從原始對象的buyBook中調用findByIsbn和deductStock不會,因此不會創建新的交易。
一個快速的周轉解決方案是,因為JdbcBookDao是一個單例,請從應用程序上下文中獲取此對象。 現在,與其直接在對象上調用方法,不如使用引用來調用它(以確保調用代理),這就是方法的外觀。
public class JdbcBookDao implements BookDao, ApplicationContextAware{private ApplicationContext context;private BookDao bookDao;public void setApplicationContext(ApplicationContext context){this.context = context;}public BookDao getBookDao(){bookDao = (BookDao)context.getBean("jdbcBookDao");}void buyBook(String isbn) throws BookNotFoundException{Book book = getBookDao().findByIsbn(isbn);if(book == null){throw new BookNotFoundException();}getBookDao().deductStock(book);}..... }剛剛實施了一個粗略的版本來使它正常工作。 我們絕對可以改進它的設計方式。 代替將應用程序上下文直接注入到DAO中,可能是我們可以使用一種輔助類來做到這一點。 或者完成此任務的另一種方法是使用程序化事務。
最后要注意的一點是,Spring僅在將公共方法標記為事務性時才管理事務。 對于私有,受保護和程序包私有的方法,Spring不提供事務管理支持。 對于動態代理,當它們實現接口時,所有事務處理方法都是公共的。 因此,無需擔心非公開方法。 對于CGLIB代理,在創建子類時僅重寫公共方法。 因此,即使在這里,也不會考慮非公開方法。
 讓我以一個問題結束這次討論。 當我嘗試使用?tx:annotation-driven proxy-target-class =” true” /?代理目標類時,它實際上不起作用,即未創建CGLIB代理 。 為此,我必須進行一些小改動。 正如Spring文檔明確指出的那樣,如果在?tx:annotation驅動的?,?aop:config?或?aop:aspectj-autoproxy?中的任何一個上啟用了代理目標類,Spring將在容器上啟用CGLIB代理創建。 因此,我只創建了一個空的?aop:config proxy-target-class =“ true” /?。 不用擔心,它開始起作用! 不知道這是否是Spring本身的錯誤。 高度贊賞,如果有人可以回答這個問題。 
翻譯自: https://www.javacodegeeks.com/2013/11/spring-transactions-visibility.html
spring和spring
總結
以上是生活随笔為你收集整理的spring和spring_Spring交易可见性的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 带有Spring Boot 2.0的Sp
- 下一篇: amd显卡切换面板快捷键(amd显卡设置
