Spring AOP управление транзакциями в Hibernate
Управление транзакциями требуется для обеспечения целостности и согласованности данных в базе данных. Техника Spring AOP позволяет разработчикам управлять декларативными транзакциями.
Вот пример, показывающий, как управлять транзакцией Hibernate с помощью Spring AOP.
P.S Many Hibernate and Spring configuration files are hidden, only some important files are shown, if you want hand-on, download the full project at the end of the article.
1. Создание таблицы
Скрипты таблиц MySQL, таблица‘product и таблицаproduct quantity on hand.
CREATE TABLE `example`.`product` ( `PRODUCT_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `PRODUCT_CODE` varchar(20) NOT NULL, `PRODUCT_DESC` varchar(255) NOT NULL, PRIMARY KEY (`PRODUCT_ID`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `example`.`product_qoh` ( `QOH_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `PRODUCT_ID` bigint(20) unsigned NOT NULL, `QTY` int(10) unsigned NOT NULL, PRIMARY KEY (`QOH_ID`), KEY `FK_product_qoh_product_id` (`PRODUCT_ID`), CONSTRAINT `FK_product_qoh_product_id` FOREIGN KEY (`PRODUCT_ID`) REFERENCES `product` (`PRODUCT_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2. Продукт Бизнес Объект
В этой реализации 'productBo' методsave() вставляет запись в таблицу 'product через класс‘productDao', а запись количества в наличии в 'productQoh 'через класс'productQohBo '.
package com.example.product.bo.impl; import com.example.product.bo.ProductBo; import com.example.product.bo.ProductQohBo; import com.example.product.dao.ProductDao; import com.example.product.model.Product; import com.example.product.model.ProductQoh; public class ProductBoImpl implements ProductBo{ ProductDao productDao; ProductQohBo productQohBo; public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void setProductQohBo(ProductQohBo productQohBo) { this.productQohBo = productQohBo; } //this method need to be transactional public void save(Product product, int qoh){ productDao.save(product); System.out.println("Product Inserted"); ProductQoh productQoh = new ProductQoh(); productQoh.setProductId(product.getProductId()); productQoh.setQty(qoh); productQohBo.save(productQoh); System.out.println("ProductQoh Inserted"); } }
Файл конфигурации bean-компонента Spring.
Запустить его
Product product = new Product(); product.setProductCode("ABC"); product.setProductDesc("This is product ABC"); ProductBo productBo = (ProductBo)appContext.getBean("productBo"); productBo.save(product, 100);
Предположим, чтоsave() не имеет транзакционной функции, если исключение выбрасываетсяproductQohBo.save(), вы вставляете запись только в таблицу 'product', запись не будет вставлена в 'productQoh 'таблица. Это серьезная проблема, которая нарушает согласованность данных в вашей базе данных.
3. Управление транзакциями
Объявлен bean-компонент «TransactionInterceptor» и «HibernateTransactionManager» для транзакции Hibernate и передано необходимое свойство.
PROPAGATION_REQUIRED
Атрибуты транзакции
В перехватчике транзакций вы должны определить, какие атрибуты транзакции «propagation behavior» следует использовать. Это означает, что если транзакционный метод‘ProductBoImpl.save() 'называется другим методом'productQohBo.save() ', как транзакция должна распространяться? Должен ли он продолжать работать в рамках существующей транзакции? или начать новую транзакцию для себя.
Spring поддерживает 7 типов распространения:
-
PROPAGATION_REQUIRED - Поддерживать текущую транзакцию; создайте новый, если его нет.
-
PROPAGATION_SUPPORTS - Поддерживать текущую транзакцию; выполнять без транзакций, если таковой не существует.
-
PROPAGATION_MANDATORY - Поддерживать текущую транзакцию; генерировать исключение, если текущая транзакция не существует.
-
PROPAGATION_REQUIRES_NEW - Создать новую транзакцию, приостановив текущую транзакцию, если таковая существует.
-
PROPAGATION_NOT_SUPPORTED - Не поддерживать текущую транзакцию; скорее, всегда выполняются без транзакций.
-
PROPAGATION_NEVER - Не поддерживать текущую транзакцию; генерировать исключение, если существует текущая транзакция.
-
PROPAGATION_NESTED - Выполнить во вложенной транзакции, если текущая транзакция существует, в противном случае вести себя как PROPAGATION_REQUIRED.
В большинстве случаев вам может понадобиться просто использовать PROPAGATION_REQUIRED.
Кроме того, вы должны определить метод для поддержки атрибутов этой транзакции. Имя метода поддерживается форматом подстановочных знаков,save * будет соответствовать всем именам методов, начинающимся с save (…).
Менеджер транзакций
В транзакции Hibernate вам необходимо использоватьHibernateTransactionManager. Если вы работаете только с чистым JDBC, используйтеDataSourceTransactionManager; пока JTA, используйтеJtaTransactionManager.
4. Proxy Factory Bean
Создайте новый компонент фабрики прокси дляProductBo и установите свойство «interceptorNames».
transactionInterceptor
Запустить его
Product product = new Product(); product.setProductCode("ABC"); product.setProductDesc("This is product ABC"); ProductBo productBo = (ProductBo)appContext.getBean("productBoProxy"); productBo.save(product, 100);
Получите свой прокси-компонент 'productBoProxy', и ваш методsave() теперь поддерживает транзакцию, любые исключения внутри методаproductBo.save() приведут к откату всей транзакции, данные не будут вставлены в базу данных .