事务的概念:
并发带来的问题:
脏读,幻读,不可重复读
事务分类: 分为基于数据库事务,和数据库连接的事务
程序事务
分布式事务
本地事务
spring的事务使用步骤:
1.获取数据库连接:所有企业都实现datasource接口,来获取connection对象
2.开启事务
3. 执行
4.事务提交或者回滚
5.事务关闭
此处先声明:spring自身没有实现事务管理,自身只有事务管理器,让不同的生成厂商自己去实现事务管理的
<!-- 事物管理配置 --> 使用spring 提供的工具类 TransctionMager 事务管理器 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
利用切面编程来实现对某一类方法进行统一管理(声明事务)
<aop:config>
<aop:advisor pointcut="execution(* com.dhcc..service..*Service*.*(..))"
advice-ref="txAdvice" />
<aop:advisor pointcut="execution(* com.dhcc..service..*Service*.*(..))"
advice-ref="druid-stat-interceptor" />
</aop:config>
一般业务都把事务放到service层
通知规则:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" propagation="REQUIRES_NEW" isolation="DEFAULT" no-rollback-for=""
rollback-for="BaseException,DataBaseException" />
<tx:method name="find*" propagation="REQUIRES_NEW"
read-only="true" />
<tx:method name="query*" propagation="REQUIRES_NEW"
read-only="true" />
<tx:method name="load*" propagation="REQUIRES_NEW" />
<tx:method name="submit*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="save*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException,Exception" />
<tx:method name="update*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="*delete*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="*add*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="change*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="execute*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="resultParse*" propagation="REQUIRED"
rollback-for="BaseException,DataBaseException" />
<tx:method name="upgrade" propagation="REQUIRES_NEW"
rollback-for="BaseException,DataBaseException" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
针对事务配置说明的几个属性进行说明:
propagation事务传播
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 |
isolation 事务隔离级别:
隔离级别 | 含义 |
---|---|
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
ISOLATION_READ_COMMITTED | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
ISOLATION_REPEATABLE_READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
ISOLATION_SERIALIZABLE | 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |
数据库隔离级别
rollback-for not-rollback-for 抛出哪些异常会回滚:
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
//捕获异常,但不处理
System.out.println("-----nothing to do-------");
}
service层有这样的异常处理事务并不会回滚:
我们必须throw 异常
只读
事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
事务超时
为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
回滚规则
事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。