2012-03-29 2 views
14

У меня есть набор из @Service beans, которые наследуют функциональность ядра от абстрактного класса. Я обозначил каждый из конкретных услуг подкласса @Service и @Transactional. Абстрактный суперкласс содержит метод публичной точки входа для каждой из этих служб. Другими словами, у меня есть что-то похожее на следующее:Правила наследования весенних @Transactional

abstract class AbstractService { 

    public void process() { 
     // Do common initialisation code here 
     processSpecific(); 
     // Do common completion code here 
    } 

    abstract protected void processSpecific(); 
} 


@Service @Transactional 
public class FirstSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do specific processing code here 
    } 
} 


@Service @Transactional 
public class SecondSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do different specific processing code here 
    } 
} 

Конкретный код в каждом конкретном суб-класса обслуживания делает несколько вызовов DAO слоя, чтобы внести изменения в базу данных, которые имеют REQUIRED как транзакционный распространения тип.

Теперь с услугами, определенными выше, я обнаружил, что не было текущей транзакции внутри какого-либо кода этих конкретных услуг подкласса, и каждый вызов уровня DAO создавал новую транзакцию, выполнял изменения, совершение транзакции и возврат.

Однако, если я аннотировать абстрактный супер-класс с @Transactional, то транзакцией является созданы должным образом, и суб-звонки в DAO слой все участвуют в текущей транзакции.

Так что мой вопрос в том, какие правила наследуют поведение @Transactional? Почему Spring не использует @Transactional в конкретных проектах подкласса, которые он фактически создает? Должен ли @Transactional быть в суперклассе в этом случае, потому что именно здесь используется общедоступный метод входа?

+0

Кстати, я взглянул на [соответствующую документацию SpringSource] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework -reference.html # transaction-declarative-annotations), но это, похоже, не охватывает этого. – DuncanKinnear

ответ

9

Из документации сделки пружинной,

Примечание: В режиме прокси (который по умолчанию), только «внешний» метод звонки, поступающие через прокси-сервер будет перехвачена. Это означает, что «самообзвон» , т. Е. Метод в целевом объекте, вызывающий другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод отмечен @Transactional!

Даже если у вас есть @Transactional на вашей конкретной реализации, и вы вызываете метод обработки, который на самом деле TRANSACTIONAL ваша аннотация, но этот метод вызывающего процесса processSpecific на ваших подклассах не является транзакционным из-за этот внутренний вызов.

Посмотрите на ткачество.

+0

Но не будет ли прокси-сервером экземпляром «FirstSpecificService»? В этом случае система будет вызывать внешний метод «process» этого экземпляра, а сам экземпляр помечен как «@ Transactional». Я полностью понимаю, что внутренние частные или защищенные методы, отмеченные как '@ Transactional', не повлияют на транзакцию, но это не то, что у меня есть. Весь мой bean-компонент отмечен как '@ Transactional'. – DuncanKinnear

+0

Нет, он не будет транзакционным, если его вызвал из внутреннего метода. Для начала, когда вы вызываете метод процесса извне, экземпляр прокси контролируется транзакцией, и когда метод процесса вызывает processSpecific, весна не знает о транзакционном потоке, поскольку точечный разрез был сделан на прокси-объекте, а не на подклассе processSpecific метод. У нас была та же проблема, и мы добавили время загрузки, и все сработало. – Kathir

+0

Кабина вы объясняете «время перемотки нагрузки» по отношению к моему примеру выше. Как это изменит код этих (надуманных) примеров услуг? – DuncanKinnear

1

Вы прочитали часть о transaction propagation и как ее можно настроить с помощью @Transactional?

Еще одна интересная тема: Spring рекомендует, чтобы вы должны были annotate concrete classes (как и против аннотированных интерфейсов).

+0

Да, как указано выше, я прочитал все эти разделы документации, и ни одно из них, похоже, не применялось в этом случае. Мой абстрактный суперкласс - это ** не ** интерфейс, это код, унаследованный фактическим конкретным подклассом. Возможно, вы можете процитировать раздел документации, который, по вашему мнению, применим к моему примеру. – DuncanKinnear

+1

Если вы хотите, чтобы ваши DAO всегда принимали участие в существующей транзакции (инициированной вашей службой), вы должны настроить DAO как @Transactional (распространение = [Propagation.MANDATORY] (http://static.springsource.org). /spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html#MANDATORY)), поскольку с помощью [ТРЕБУЕТСЯ] (http://static.springsource.org/spring/docs/3.1 .x/javadoc-api/org/springframework/transaction/annotation/Propagation.html # REQUIRED) создаст новую транзакцию, если она не существует. – matsev

+0

Да, это будет способ для нас поймать эти проблемы в будущем, но он все еще не объясняет, что такое правила наследования. – DuncanKinnear

Смежные вопросы