Spring – 33 – Aspect Oriented Programming (AOP) – 07 – JPA & Hibernate AspectJ Declarative Transaction Management
Merhaba Arkadaslar
Onceki bolumlerde Declarative Transaction yaklasimini @Transactional annotation ile kullandik.
Bu bolumde AOP yaklasimiyla , Declarative Transaction yonetiminini inceleyelim.
- JPA/EclipseLink
- Native Hibernate icin ornek yapalim.
Declarative Transaction yaklasimini su bolumde inceledik ;
Spring – 26 – Declarative Transaction JPA & Hibernate
Burada ilgili siniflari tekrar kullanacagiz , bu nedenle tum class’lari burada paylasmiyorum.
CustomerServiceImpl.java
CustomerServiceImpl sinifimizda @Transactional annotation kullanmamiza gerek yok.
Declarative Transaction yonetimini AOP yardimiyla gerceklestirecegiz.
package _38.aspectj.jpa.transaction.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import _38.aspectj.jpa.transaction.dao.AddressDAO; import _38.aspectj.jpa.transaction.dao.CustomerDAO; import _38.aspectj.jpa.transaction.model.Customer; @Service public class CustomerServiceImpl implements CustomerService{ @Autowired private CustomerDAO customerDAO; @Autowired private AddressDAO addressDao; @Override public void insertCustomerData(Customer customer) { customerDAO.insertCustomer(customer); addressDao.insertAddress(customer.getAddress()); } @Override public List listCustomers() { return customerDAO.findAllCustomers(); } }
38.aspectj.jpa.transaction.xml
XML configuration dosyamizi inceleyecek olursak entityManagerFactory ile ilgili ayarlardan onceki bolumlerden bahsetmistim.
tx:advice tag’inda transaction-manager attribute’e tanimladigimiz JpaTransactionManager bean id bilgisini veriyoruz.
list* ve get* metotlari veritabaninda ekleme guncelleme islemi olmayacagi icin read only olarak belirtiyoruz.
aop:config tag’imizda expression attribute’te service paketimizde yer alan siniflarin tamamini belirtiyoruz.
advice-ref olarak txAdvice’i veriyoruz.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!-- scan packages --> <context:component-scan base-package="_38.aspectj.jpa.transaction.dao , _38.aspectj.jpa.transaction.service " /> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>jdbc/jdbc.properties</value> </property> </bean> <bean id="dataSourceId" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSourceId" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" /> </property> <property name="packagesToScan" value="_38.aspectj.jpa.transaction.model" /> <property name="jpaProperties"> <props> <prop key="eclipselink.ddl-generation">drop-and-create-tables</prop> <prop key="eclipselink.logging.level">OFF</prop> <prop key="hibernate.hbm2ddl.auto">create-drop</prop> </props> </property> <property name="jpaPropertyMap"> <map> <entry key="eclipselink.weaving" value="false" /> </map> </property> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- all methods starting with 'list' or 'get' are read-only --> <tx:method name="list*" read-only="true"/> <tx:method name="get*" read-only="true"/> <!-- for other methods use the default transaction settings --> <tx:method name="*" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* _38.aspectj.jpa.transaction.service.*.*(..))" /> <aop:advisor pointcut-ref="serviceMethods" advice-ref="txAdvice" /> </aop:config> <!-- TransactionManager --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
AspectJJPATransactionTest.java
package _38.aspectj.jpa.transaction.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import _38.aspectj.jpa.transaction.model.Address; import _38.aspectj.jpa.transaction.model.Customer; import _38.aspectj.jpa.transaction.service.CustomerService; public class AspectJJPATransactionTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("38.aspectj.jpa.transaction.xml"); // get CustomerService bean CustomerService customerService = context.getBean(CustomerService.class); // prepare Customer and Address data. Customer customer = new Customer(1, "Levent", "Erguder"); Address address = new Address(1, "Java Street", "34000", "Istanbul"); customer.setAddress(address); // Customer customer2 = new Customer(2, "Orcun", "Erpis"); Address address2 = new Address(2, "Bakanliklar Street", "06000", "Ankara"); customer2.setAddress(address2); Customer customer3 = new Customer(3, "Hakan", "Gencel"); // duplicate Address id , throw exception // customers3 record will be rollbacked too. Address address3 = new Address(2, "Alemdag Road", "34000", "Istanbul"); customer3.setAddress(address3); customerService.insertCustomerData(customer); customerService.insertCustomerData(customer2); try { customerService.insertCustomerData(customer3); } catch (Exception e) { System.out.println("Rollback..."); System.out.println(e.getMessage()); } System.out.println("Customer List : "); for (Customer customerRecord : customerService.listCustomers()) { System.out.println(customerRecord); } context.close(); } }
Ornegimizi calistirdigimizda;
Rollback... Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '2' for key 'PRIMARY' Error Code: 1062 Call: INSERT INTO ADDRESS (ADDRESSID, CITY, STREET, ZIPCODE) VALUES (?, ?, ?, ?) bind => [4 parameters bound] Query: InsertObjectQuery(Address [addressId=2, street=Alemdag Road, zipcode=34000, city=Istanbul]) Customer List : Customer [id=1, name=Levent, surname=Erguder, address=Address [addressId=1, street=Java Street, zipcode=34000, city=Istanbul]] Customer [id=2, name=Orcun, surname=Erpis, address=Address [addressId=2, street=Bakanliklar Street, zipcode=06000, city=Ankara]]
39.aspectj.hibernate.transaction.xml
Ayni ornegimizi Hibernate icin yapalim.
transactionManager icin HibernateTransactionManager bean tanimini yapalim.
sessionFactory icin LocalSessionFactoryBean kullaniyoruz.
aop:config ve tx:advice taglari yine benzer sekilde olacak.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!-- scan packages --> <context:component-scan base-package="_39.aspectj.hibernate.transaction.dao , _39.aspectj.hibernate.transaction.service " /> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>jdbc/jdbc.properties</value> </property> </bean> <bean id="dataSourceId" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSourceId" /> <property name="packagesToScan" value="_39.aspectj.hibernate.transaction.model" /> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.hbm2ddl.auto">create-drop</prop> </props> </property> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- all methods starting with 'list' or 'get' are read-only --> <tx:method name="list*" read-only="true"/> <tx:method name="get*" read-only="true"/> <!-- for other methods use the default transaction settings --> <tx:method name="*" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* _39.aspectj.hibernate.transaction.service.*.*(..))" /> <aop:advisor pointcut-ref="serviceMethods" advice-ref="txAdvice" /> </aop:config> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
Ornegimizi calistirdigimizda ;
ERROR: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement] Rollback... could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement Customer List : Nov 20, 2016 12:19:08 PM org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService INFO: HHH000397: Using ASTQueryTranslatorFactory Customer [id=1, name=Levent, surname=Erguder, address=Address [addressId=1, street=Java Street, zipcode=34000, city=Istanbul]] Customer [id=2, name=Orcun, surname=Erpis, address=Address [addressId=2, street=Bakanliklar Street, zipcode=06000, city=Ankara]]
Github kaynak dosyalar/ source folder
leventerguder/injavawetrust-spring-tutorial
Yazimi burada sonlandiriyorum.
Herkese bol Javali gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer
Leave a Reply