什么是事务:java
事务指的是逻辑上的一组操做,这组操做要么所有成功,要么所有失败。mysql
事务的特性:git
原子性,隔离性,一致性,持久性。spring
原子性:指的是事务是一个不可分割的工做单位,事务的发生要么所有发生,要么所有都不发生。sql
隔离性:指的是当多个用户并发访问数据库时,一个用户的事务不能被其余用户的事务所干扰,多个并发事务之间数据要相互隔离。数据库
一致性:指事务发生后,先后的数据完整性必须保持一致。express
持久性:当事务必定提交,他对数据库中的数据的改变是永久的,即便数据库发生故障也不该该对其有任何影响。编程
Spring 事务管理高层抽象主要包括了3个接口:后端
platFormTransactionManager 事务管理器并发
TransactionDefinition 事务定义信息(隔离,传播,超时,只读)
TransactionStatus 事务具体运行状态
(1)platFormTranscationManager 是一个接口 有不少针对不一样持久层的框架去选择不一样的事务管理器
事务 | 说明 |
org.sprinframework.jdbc.datasource.DataSourceTransactionManager |
使用Spring JDBC或iBatis进行持久化数据时使用 |
org.springframework.orm.hibernate3.HibernateTranscationManager | 使用Hiber3.0版本进行持久化数据时使用 |
org.springframework.orm.jpa.JpaTranscationManager | 使用JPA进行持久化时使用 |
org.springframework.jdo.JdoTranscationManager |
当持久化机制是jdo时使用 |
org.springframework.transaction.jta.JtaTranscationManager | 使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用 |
(2)TranscationDefinition
TransactionDefinition接口的常量中ISOLATION_开头的表示事物的隔离级别(4种)
没有的话隔离级别,会出现的问题:
脏读:一个事务读取到另一个事务改写但还未提交的数据。若是这些数据被回滚,则读到的数据是无效的。
不可重复读:在同一个事务中,读到了另外一个事务已经提交更新的数据返回结果不同,致使这个事务中先后的查询结果不一致。
虚读或幻读:一个事务读取一些数据以后,另外一个事务插入了一些记录,而致使这个事务中查询的数据不一致。(第二次读取,会读取到插入后一些数据)
看了上面的解释,感受不可重复读和幻读很相似。
特地查一下资料:
不可重复读的重点在修改,你先后读取到的数据是不同。
例子(我随便想的,可能不对):事务1,a查询卡里有1000元,事务2,有人转500到你的卡里,事务1尚未结束,它再次查询卡里的金额,显示为1500元。同一个事务中先后读取的信息不一致。
幻读的重点在新增或删除,一样的条件, 第1次和第2次读出来的记录数不同。
例子(网上找的):目前工资为1000的员工有10人。 事务1,读取全部工资为1000的员工。 这时另外一个事务向employee表插入了一条员工记录,工资也为1000 ,事务1再次读取全部工资为1000的员工 共读取到了11条记录,这就产生了幻像读。
隔离级别 | 含义 |
DEFAULT | 使用后端数据库默认的隔离级别(spring中的选择项) |
READ_UNCOMMITED | 容许你读取还未提交的改变了得数据,可能致使脏读,幻读,不可重复读 |
READ_COMMITED | 容许在并发事务已经提交读取,可防止脏读,但幻读和不可重复读仍可发生 |
REPEATABLE_READ | 对相同字段的屡次读取是一致的,除非数据被事务自己改变。可防止脏,不可重复读,但幻读仍可发生 |
SERIALIZABLE | 彻底服从ACID(数据库事务的四要素)的隔离级别,确保不发生脏,幻,不可重复读。这在全部的隔离级别中是最慢的。他是典型的经过彻底锁定在事务中涉及的数据表完成的。 |
mysql默认采用REPEATABLE_READ隔离级别
oracle默认采用READ_COMMITED隔离级别
TransactionDefinition接口的常量中PROPAGATION开头的表示事物的传播行为(7种)
当出现复杂状况时,好比某一个业务调用的业务层中的另外二个业务,每一个业务都里面都有事务。
事务的传播行为:解决业务层方法之间的相互调用的问
事务传播行为类型 | 说明 |
PROPAGATION_REQUIRED | 支持当前事务,若是不存在,就新建一个 |
PROPAGATION_SUPPORTS | 支持当前事务,若是不存在,就不使用事务 |
PROPAGATION_MANDATORY | 支持当前事务,若是不存在,抛出异常 |
PROPAGATION_REQUIRES_NEW | 若是有事务存在,挂起当前事务,建立一个新的事务 |
PROPAGATION_NOT_SUPPORTED | 以非事务运行,若是有事务存在,挂起当前事务 |
PROPAGATION_NEVER | 以非事务运行,若是有事务存在,抛出异常 |
PROPAGATION_NESTED | 若是当前事务存在,则嵌套事务存在 |
Spring事务管理
Spring支持两种方式事务管理
--编程式的事务管理
在实际应用中不多使用
经过TranscationTemplate手动管理事务
--使用xml配置声明式事务
开发中推荐使用(代码侵入性最小)
Spring的声明式事务时经过aop实现的
用转帐系统的事务管理。
编程式的事务管理,在xml上配置:
<!-- 引入外部的属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置c3p0链接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置业务层类 --> <bean id="accountService" class="com.spring.demo1.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> <!-- 注入事务管理的模板 --> <property name="transactionTemplate" ref="transactionTemplate" /> </bean> <!-- 配置DAO类(简化,会自动配置JdbcTemplate) --> <bean id="accountDao" class="com.spring.demo1.AccountDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> </bean>
在转帐业务上 注入事务管理的模板
@Override public void transfer(final String out, final String in, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.outMoney(out, money); //int i = 1/0; accountDao.inMoney(in, money); } }); }
基于代理的声明式的事务管理
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置业务层的代理 --> <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置目标对象 --> <property name="target" ref="accountService" /> <!-- 注入事务管理器 --> <property name="transactionManager" ref="transactionManager" /> <!-- 注入事务的属性 --> <property name="transactionAttributes"> <props> <!-- prop的格式: * PROPAGATION :事务的传播行为 * ISOTATION :事务的隔离级别 * readOnly :只读 * -EXCEPTION :发生哪些异常回滚事务 * +EXCEPTION :发生哪些异常不回滚事务 --> <prop key="transfer">PROPAGATION_REQUIRED</prop> <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> --> <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> --> </props> </property> </bean>
在转帐业务上
@Override public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); //int i = 1/0; accountDao.inMoney(in, money); }
使用XML配置声明式的事务管理,基于tx/aop
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务的增长 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED"/> <!-- propagation : 事务的传播行为 isolation : 事务隔离级别 read-only : 只读 rollback-for :发生那些异常回来 no-rollback-for : 发生哪些一场不回滚 timeout :过时信息 --> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* com.spring.demo3.AccountService+.*(..))" id="pointcut1"/> <!-- 配置切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config>
业务代码
@Override public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); int i = 1/0; accountDao.inMoney(in, money); }
基于注解的事务管理的方式
<!-- ==================================4.基于注解的的事务管理 =============================================== --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager"/>
业务代码
/** * @Transactional 注解中的属性: * propagation :事务的传播行为 * isolation :事务的隔离级别 * readOnly :只读 * rollbackFor :发生哪些异常回滚 * noRollbackFor :发生那些异常不回滚 * @author mufeng * */ @Override public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); int i = 1/0; accountDao.inMoney(in, money); }