Spring事務管理——AOP注解事務管理
數據庫事務(簡稱:事務)是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。
一個數據庫事務通常包含了一個序列的對數據庫的讀/寫操作。它的存在包含有以下兩個目的:
為數據庫操作序列提供了一個從失敗中恢復到正常狀態的方法,同時提供了數據庫即使在異常狀態下仍能保持一致性的方法。 當多個應用程序在并發訪問數據庫時,可以在這些應用程序之間提供一個隔離方法,以防止彼此的操作互相干擾。
當事務被提交給了DBMS(數據庫管理系統),則DBMS(數據庫管理系統)需要確保該事務中的所有操作都成功完成且其結果被永久保存在數據庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要被回滾,回到事務執行前的狀態;同時,該事務對數據庫或者其他事務的執行無影響,所有的事務都好像在獨立的運行。
特性
并非任意的對數據庫的操作序列都是數據庫事務。數據庫事務擁有以下四個特性,習慣上被稱之為ACID特性。
原子性(Atomicity):事務作為一個整體被執行,包含在其中的對數據庫的操作要么全部被執行,要么都不執行。
一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變為另一個一致狀態。一致狀態的含義是數據庫中的數據應滿足完整性約束。
隔離性(Isolation):多個事務并發執行時,一個事務的執行不應影響其他事務的執行。
持久性(Durability):已被提交的事務對數據庫的修改應該永久保存在數據庫中。
Spring下由三種途徑對事物進行管理:編程式事務管理、聲明式事務管理和AOP事務管理。其中AOP事務管理又分AOP注解事務管理和AOP XML配置兩種
AOP注解事務管理
spring.xml
(spring的配置文件,不一定叫spring.xml)文件中的配置:
1.配置數據源(我使用的是tddl,改為自己的數據源)
<!-- datasource begin -->
<bean id="tddlGroupDataSource" class="com.taobao.tddl.jdbc.group.TGroupDataSource"
init-method="init">
<property name="appName" value="${alibaba.intl.apaas.db.app.name}"/>
<property name="dbGroupKey" value="${alibaba.intl.apaas.db.group.key}"/>
</bean>
<!-- datasource end -->
2. 配置sping的事務管理
<beans xmlns="
</beans></code></pre>
<tx:annotation-driven transaction-manager="transactionManager" />
這句話加上的話,在spring獲取bean的時候,要使用接口!
3.配置SqlMapClient(我的持久層使用了ibatis,所以需要配置這個)
<bean id="apaasSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="biz/sql-map-config.xml"/>
<property name="dataSource" ref="tddlGroupDataSource"/>
</bean>
sql-map-config.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
";
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
errorTracingEnabled="true" lazyLoadingEnabled="true" maxRequests="32"
maxSessions="10" maxTransactions="5" useStatementNamespaces="true" />
<sqlMap resource="sqlmap/sqlmap-apaas-label.xml" />
<!-- <sqlMap resource="sqlmap/sqlmap-apaas-label-sorce.xml" /> -->
</sqlMapConfig></code></pre>
sqlmap-apaas-label-sorce.xml配置就不寫了,就是ibatis的jdbc操作。
4.配置dao和service
<bean id="appLabelDao" class="com.alibaba.intl.apaas.common.monitor.dao.impl.AppLabelDaoImpl"
parent="baseSqlMapClientDAO"/>
<bean id="appLabelServiceBean" class="com.alibaba.intl.apaas.common.monitor.service.impl.AppLabelServiceImpl">
<property name="appLabelDao">
<ref bean="appLabelDao"/>
</property>
</bean>
AppLabelServiceImpl
的Java類的配置:
public class AppLabelServiceImpl implements AppLabelService {
private AppLabelDao appLabelDao;
@Transactional
public Integer insertAppLabel() {
appLabelDao.jdbcOperate1();
appLabelDao.jdbcOperate2();
appLabelDao.jdbcOperate3();
appLabelDao.jdbcOperate4();
}
}
這里使用@Transactional
這個注解,這個注解的原理和具體使用方式我會在別的文章里面介紹。 在方法insertAppLabel
上添加@Transactional
這個注解,聲明該方法要在一個事務中進行處理。 這個方法一共有四個jdbc操作jdbcOperate1
、jdbcOperate2
、jdbcOperate3
、jdbcOperate4
,如果在整個insertAppLabel
方法的任何地方拋出runtimeException,就會執行rollback。即所有操作將被回滾。
測試類:
public class AppLabelServiceImplTest {
private static AppLabelService service;
@BeforeClass
public static void beforeClass() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:biz/sca-appinfo-provider-context.xml");
service = (AppLabelService)context.getBean("appLabelServiceBean");
}
@Test
public void testInsert(){
service.insertAppLabel( );
}
}
PS:service = (AppLabelService)context.getBean("appLabelServiceBean");
此處應該注意,一定要用AppLabelService
這個接口,二不能用AppLabelServiceImpl
這個實現類。 因為Spring文檔中有寫:Spring AOP部分使用JDK動態代理或者CGLIB來為目標對象創建代理,如果被代理的目標對象實現了至少一個接口,則會使用JDK動態代理。所有該目標類型實現的接口都將被代理。若該目標對象沒有實現任何接口,則創建一個CGLIB代理。
如果不使用AppLabelService而使用AppLabelServiceImpl的話,在執行程序的時候就會報錯:classCastException
這里,service也不能是new出來的,必須要用spring進行管理。
來自:http://www.hollischuang.com/archives/297