在MySQL經常使用的存儲引擎中, 只有InnoDB支持事務, 因此這裏說的隔離級別指的是InnoDB下的事務隔離級別.java
隔離級別 | 讀數據一致性 | 更新丟失 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|---|---|
讀未提交 | 最低級別, 只能保證不讀取物理上損壞的數據 | × | √ | √ | √ |
讀已提交 | 語句級 | × | × | √ | √ |
可重複讀 | 事務級 | × | × | × | × |
可串行化 | 最高級別, 事務級 | × | × | × | × |
下面是Spring事務註解的源代碼, 從中能夠看到Spring事務管理的四個屬性: Propagation, Isolation, timeout, readOnly.mysql
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
複製代碼
事務傳播行爲spring
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
private final int value;
private Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
複製代碼
事務傳播行爲是指方法之間事務的傳播. 好比, 在方法A中調用了方法B:sql
public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
private final int value;
private Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
複製代碼
其中 DEFAULT 表示使用數據庫的隔離級別.數據庫
爲了解決事務執行時間太長, 消耗太多資源的問題, 咱們能夠給事務設置一個超時時間, 若是事務執行時間超過了超時時間, 就回滾事務.編程
一些不須要事務的方法, 好比讀取數據, 就能夠設置爲只讀事務, 這樣能夠有效地提升一些性能.後端
Spring使用 TransactionTemplate 事務模板來管理事務.bash
(1)dao層架構
public interface AccountDao {
//匯款
public void out(String outer , Integer money);
//收款
public void in(String inner , Integer money);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
public void out(String outer, Integer money) {
this.getJdbcTemplate().update("update account set money = money - ? where username = ?", money,outer);
}
public void in(String inner, Integer money) {
this.getJdbcTemplate().update("update account set money = money + ? where username = ?", money,inner);
}
}
複製代碼
(2)Service層併發
public interface AccountService {
//轉帳
public void transfer(String outer ,String inner ,Integer money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
private TransactionTemplate transactionTemplate;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(final String outer, final String inner, final Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.out(outer, money);
//模擬故障
int i = 1/0;
accountDao.in(inner, money);
}
});
}
}
複製代碼
(3)Spring配置
<beans>
<!-- 一、datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="123"></property>
</bean>
<!-- 二、dao -->
<bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 三、service -->
<bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
<!-- 四、建立事務模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"></property>
</bean>
<!-- 五、配置事務管理器 ,管理器須要事務,事務從Connection得到,鏈接從鏈接池DataSource得到 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
複製代碼
(4)測試代碼
@Test
public void demo(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("jack", "rose", 1000);
}
複製代碼
(1)Service層
public interface AccountService {
//轉帳
public void transfer(String outer ,String inner ,Integer money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
//模擬故障
int i = 1/0;
accountDao.in(inner, money);
}
}
複製代碼
(2)Spring配置文件
<beans>
<!-- 一、datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="123"></property>
</bean>
<!-- 二、dao -->
<bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 三、service -->
<bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 四、service 代理對象
4.1 proxyInterfaces 接口
4.2 target 目標類
4.3 transactionManager 事務管理器
4.4 transactionAttributes 事務屬性(事務詳情)
prop.key :肯定哪些方法使用當前事務配置
prop.text:用於配置事務詳情
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
傳播行爲 隔離級別 是否只讀 異常回滾 異常提交
例如:
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默認傳播行爲,和隔離級別
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只讀
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop> 有異常扔提交
-->
<bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces" value="org.tx.service.AccountService"></property>
<property name="target" ref="accountService"></property>
<property name="transactionManager" ref="txManager"></property>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
</props>
</property>
</bean>
<!-- 五、配置事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
複製代碼
(3)測試代碼
@Test
public void demo(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("proxyAccountService");
accountService.transfer("jack", "rose", 1000);
}
複製代碼
(1)Service層
public interface AccountService {
//轉帳
public void transfer(String outer ,String inner ,Integer money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
//模擬故障
int i = 1/0;
accountDao.in(inner, money);
}
}
複製代碼
(2)Spring配置文件
<beans>
<!-- 一、datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="123"></property>
</bean>
<!-- 二、dao -->
<bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 三、service -->
<bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 四、事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 五、事務通知
<tx:attributes> 用於配置事務詳情(事務屬性)
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 六、AOP編程 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* org.tx.service.*.*(..))"/>
</aop:config>
</beans>
複製代碼
(3)測試代碼
@Test
public void demo(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("jack", "rose", 1000);
}
複製代碼
(1)Service層
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//或者 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
//模擬故障
int i = 1/0;
accountDao.in(inner, money);
}
}
複製代碼
(2)Spring配置文件
<beans>
<!-- 一、datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="123"></property>
</bean>
<!-- 二、dao -->
<bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 三、service -->
<bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 四、事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 五、將事務管理器交予Spring -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
複製代碼
(3)測試代碼
@Test
public void demo(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("jack", "rose", 1000);
}
複製代碼
來源: blog.csdn.net/litianxiang…
做者的開源項目推薦:
關注公衆號回覆開源項目
便可獲取