Я новичок в Spring Transaction. Что-то, что я нашел действительно странным, наверное, я правильно понял.
Я хотел иметь транзакционный уровень на уровне метода, и у меня есть метод вызывающего в том же классе, и кажется, что это не нравится, его нужно вызывать из отдельного класса. Я не понимаю, как такое возможно.
Если у кого-то есть идея, как решить эту проблему, я был бы очень признателен. Я хотел бы использовать тот же класс для вызова аннотированного транзакционного метода.
Вот код:
public class UserService {
@Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
java
spring
aspectj
spring-aop
Майк
источник
источник
TransactionTemplate
подход: stackoverflow.com/a/52989925/355438Ответы:
Это ограничение Spring AOP (динамические объекты и cglib ).
Если вы настроите Spring для использования AspectJ для обработки транзакций, ваш код будет работать.
Простая и, вероятно, лучшая альтернатива - рефакторинг вашего кода. Например, один класс, который обрабатывает пользователей, и один, который обрабатывает каждого пользователя. Тогда будет работать обработка транзакций по умолчанию с помощью Spring AOP.
Советы по настройке для обработки транзакций с AspectJ
Чтобы Spring мог использовать AspectJ для транзакций, вы должны установить режим AspectJ:
Если вы используете Spring с более ранней версией, чем 3.0, вы также должны добавить это в свою конфигурацию Spring:
источник
Проблема здесь в том, что прокси Spring AOP не расширяют, а скорее обертывают ваш экземпляр службы для перехвата вызовов. Это приводит к тому, что любой вызов this из вашего экземпляра службы напрямую вызывается в этом экземпляре и не может быть перехвачен прокси-сервером-оболочкой (прокси даже не знает ни о каком таком вызове). Одно из решений уже упоминалось. Еще один отличный вариант - просто заставить Spring внедрить экземпляр службы в саму службу и вызвать ваш метод для внедренного экземпляра, который будет прокси-сервером, который обрабатывает ваши транзакции. Но имейте в виду, что это также может иметь плохие побочные эффекты, если ваш служебный компонент не является синглтоном:
источник
UserService
есть синглтон? Что, если это один и тот же объект?С Spring 4 возможно автоматическое подключение
источник
Начиная с Java 8 есть еще одна возможность, которую я предпочитаю по причинам, указанным ниже:
Такой подход имеет следующие преимущества:
1) Может применяться к приватным методам. Таким образом, вам не нужно нарушать инкапсуляцию, делая метод общедоступным, чтобы удовлетворить ограничения Spring.
2) Один и тот же метод может быть вызван при разном распространении транзакции, и вызывающий должен выбрать подходящий. Сравните эти 2 строки:
3) Он явный, поэтому более читаемый.
источник
TransactionHandler
как подкласс, и подклассTransactionHandler
вызовет эти два метода в суперклассе, смогу ли я по-прежнему получить преимущества,@Transactional
как задумано?Это мое решение для самостоятельного вызова :
источник
Вы можете автоматически подключить BeanFactory внутри того же класса и выполнить
getBean(YourClazz.class)
Он автоматически проксифицирует ваш класс и примет во внимание вашу @Transactional или другую аннотацию aop.
источник
Проблема связана с тем, как классы Spring загружают и прокси. Это не сработает, пока вы не напишете свой внутренний метод / транзакцию в другом классе или не перейдете в другой класс, а затем снова войдете в свой класс, а затем напишете внутренний вложенный метод транскации.
Подводя итог, прокси-серверы Spring не допускают сценариев, с которыми вы сталкиваетесь. вам нужно написать второй метод транзакции в другом классе
источник
Вот что я делаю для небольших проектов с минимальным использованием вызовов методов в одном классе. Настоятельно рекомендуется внутренняя документация, поскольку она может показаться коллегам странной. Но он работает с синглтонами , легко тестируется, прост, быстро реализуется и избавляет меня от полноценного инструментария AspectJ. Однако для более интенсивного использования я бы посоветовал решение AspectJ, как описано в ответе Эспенса.
источник