在MySQL常用的存储引擎中, 只有InnoDB支持事务, 所以这里说的隔离级别指的是InnoDB下的事务隔离级别.
隔离级别 | 读数据一致性 | 更新丢失 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|---|
读未提交 | 最低级别, 只能保证不读取物理上损坏的数据 | × | √ | √ | √ |
读已提交 | 语句级 | × | × | √ | √ |
可重复读 | 事务级 | × | × | × | × |
可串行化 | 最高级别, 事务级 | × | × | × | × |
下面是Spring事务注解的源代码, 从中可以看到Spring事务管理的四个属性: Propagation, Isolation, timeout, readOnly.
@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 {}; } 复制代码
事务传播行为
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:
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 事务模板来管理事务.
(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> <!-- 1、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> <!-- 2、dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 3、service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <!-- 4、创建事务模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"></property> </bean> <!-- 5、配置事务管理器 ,管理器需要事务,事务从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> <!-- 1、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> <!-- 2、dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 3、service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 4、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> <!-- 5、配置事务管理器 --> <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> <!-- 1、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> <!-- 2、dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 3、service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 4、事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 5、事务通知 <tx:attributes> 用于配置事务详情(事务属性) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <!-- 6、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> <!-- 1、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> <!-- 2、dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 3、service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 4、事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 5、将事务管理器交予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…
作者的开源项目推荐:
关注公众号回复 开源项目
即可获取