一.编程式事务

整个事务管理的操作都是程序员通过代码自己进行编写和管理的

二.声明式事务

整个事务操作由其他框架进行管理,我们想要使用只需要在程序中进行简单的配置/声明即可—-Spring Tx
在进行声明式事务的时候 一定注意不要自己捕获异常,一定要把异常抛出去,否则配置的声明式事务就不会在起作用

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="http://www.springframework.org/schema/beans
  8. https://www.springframework.org/schema/beans/spring-beans.xsd
  9. http://www.springframework.org/schema/context
  10. https://www.springframework.org/schema/context/spring-context.xsd
  11. http://www.springframework.org/schema/aop
  12. https://www.springframework.org/schema/aop/spring-aop.xsd
  13. http://www.springframework.org/schema/tx
  14. https://www.springframework.org/schema/tx/spring-tx.xsd">
  15. <!--IOC+DI扫描-->
  16. <context:component-scan base-package="com.bjsxt.service,com.bjsxt.pojo"></context:component-scan>
  17. <!--引入属性文件-->
  18. <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
  19. <!--[1] 建立数据库连接-->
  20. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  21. <property name="driverClassName" value="${m_driver}"></property>
  22. <property name="url" value="${m_url}"></property>
  23. <property name="username" value="${m_username}"></property>
  24. <property name="password" value="${m_password}"></property>
  25. </bean>
  26. <!--[2] 获取sqlsessionfactory对象-->
  27. <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
  28. <property name="dataSource" ref="dataSource"></property>
  29. <property name="typeAliasesPackage" value="com.bjsxt.pojo"></property>
  30. </bean>
  31. <!--[3] 扫描mapper文件-->
  32. <bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  33. <property name="sqlSessionFactoryBeanName" value="factory"></property>
  34. <property name="basePackage" value="com.bjsxt.mapper"></property>
  35. <!--自动创建了Peoplemapper Bean对象-->
  36. </bean>
  37. <bean id="accountService" class="com.bjsxt.service.impl.AccountServiceImpl">
  38. <property name="accountMapper" ref="accountMapper"></property>
  39. </bean>
  40. <!--声明式事务的配置-->
  41. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  42. <property name="dataSource" ref="dataSource"></property>
  43. </bean>
  44. <!--配置事务通知-->
  45. <tx:advice transaction-manager="transactionManager" id="tx" >
  46. <tx:attributes>
  47. <tx:method name="zq*"/>
  48. </tx:attributes>
  49. </tx:advice>
  50. <aop:config>
  51. <aop:pointcut id="pt1" expression="execution(* com.bjsxt.service.impl.*.*(..))"/>
  52. <aop:advisor advice-ref="tx" pointcut-ref="pt1"></aop:advisor>
  53. </aop:config>
  54. </beans>

2.1声明式事务中属性解释:

[1] name
哪些方法需要有事务控制 支持*通配符
[2] readonly=”boolean”
是否是只读事务.
如果为true,告诉数据库此事务为只读事务.数据化优化,会对性能有一定提升,所以只要是查询的方法,建议使用此数据.不可以进行写操作
如果为false(默认值),事务需要提交的事务.建议新增,删除,修改.
[3]事务超时属性timeout(秒为单位)
timeout是设置超时属性。以秒为单位。当两秒钟时间内不能完成所有操作,就会抛异常。
spring进行事务管理中使用try-catch容器将不再管理事务。但是在catch中书写throw e将正常执行spring的事务管理
[4]rollback-for=”异常类型全限定路径”

  • 当出现什么异常时需要进行回滚
  • 建议:给定该属性值.
  • 手动抛异常一定要给该属性值.

[5] no-rollback-for=””
当出现什么异常时不滚回事务.
image.png

Propagation

三.控制事务传播行为

required:默认 如果当前有事务就在事务中执行,如果当前没有事务,新建一个事务。
supports:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务下执行。
mandatory:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错
requires_new:必须在事务中执行,如果当前没有事务,新建事务,如果当前有事务,把当前事务挂起
not_supported:必须在非事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前的事务挂起
never:必须在非事务状态下执行,如果当前没有事务,正常执行,如果当前有事务,报错
nested:必须在事务状态下执行,如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务(嵌套中的事务都执行)

四.事务隔离级别

在多线程或者并发访问下如何保证访问到的数据具有完整性

4.1脏读

脏读就是指当事务A对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务B也访问了这个数据,然后使用了这个数据。(读取了没有提交到数据库中的数据)

4.2不可重复读

在事务1中,读取了一个数据,事务1还没有结束时,事务2也访问了这个数据,修改了这个数据,并提交,紧接着,事务1又读取数据。由于事务2的修改,那么事务1两次读到的数据可能是不一样的,因此称为不可重复读。

4.3幻读

当某个事务在读取某个范围的记录时,另外一个事务又在该范围插入了新的记录,当之前的事务再次读取该范围的记录时,产生幻行。InnoDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。
注意:不可重复读和幻读的区别是:前者是指读到了已经提交的事务的更改数据(修改或删除),后者是指读到了其他已经提交事务的新增数据。
对于这两种问题解决采用不同的办法,防止读到更改数据,只需对操作的数据添加行级锁,防止操作中的数据发生变化;而防止读到新增数据,往往需要添加表级锁,将整张表锁定,防止新增数据(oracle采用多版本数据的方式实现)。

4.4隔离级别

  1. DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离界别
  2. READ_UNCOMMITTED: 可以读取未提交数据,可能出现脏读,不重复读,幻读. 效率最高.
  3. READ_COMMITTED:只能读取其他事务已提交数据.可以防止脏读,可能出现不可重复读和幻读.
  4. REPEATABLE_READ: 读取的数据被添加锁,防止其他事务修改此数据,可以防止不可重复读.脏读,可能出现幻读.
  5. SERIALIZABLE: 排队操作,对整个表添加锁.一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表。最安全的 效率最低的。