Spring分为编程式事务和声明式事务
声明式事务:
Spring给了一个约定(AOP开发也给了我们一个约定),如果使用的是声明式事务,那么当你的业务方法不发生异常(或者发生异常,但该异常也被配置信息允许提交事务)时,Spring就会让事务管理器提交事务,而发生异常(并且该异常不被你的配置信息所允许提交事务)时,则让事务管理器回滚事务。
编程式需要自己手动写事务的回滚
配置位置文件
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="password" value="${jdbc.password}"></property> <property name="username" value="${jdbc.username}"></property> </bean> <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.mapper"></property> <!-- 当使用自动注入的时候, --> <property name="sqlSessionFactoryBeanName" value="factory"></property> </bean> <!-- 声明式事务 --> <bean id="txmanager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置声明式事务 --> <tx:advice id="txadvice" transaction-manager="txmanager"> <!-- 设置那些方法需要事务管理 方法以in开头的 --> <tx:attributes>
<tx:method name="in*" propagation="REQUIRED"/>
<tx:method name="in*" read-only="true"/>
</tx:attributes> </tx:advice> <aop:config> <aop:aspect> <aop:pointcut expression="execution(* DeclarativeTransaction.*.*())" id="mypoint"/> <aop:before method="txadvice" pointcut-ref="mypoint"/> </aop:aspect> </aop:config> </beans>
Name表示要那些方法需要控制 支持通配符*
read-only="true"表示只读事务如果true表示只读事务数据库会优化,会对性能由一定的提升,只要是查询的方法建议使用
false为需要提交的事务
Propagation:控制事务传播,传播行为
当一个具有事务控制的方法,另外一个具有事务控制的方法调用后,需要如何管理事务
propagation里面有7个属性:
REQUIRED(默认值):表示如果当前有事务,就在事务中执行,如果没有就新建一个事务
SUPPORTS:表示如果当前有事务,就在事务中执行,如果没有就在一个非事务的状态执行
MANDATORY:必须在事务中执行,如果有事务就在事务中执行,如果没有事务就报错
REQUIRES_NEW:必须在事务中执行,,表示如果当前没有有事务,就在事务中执行,如果没有就新建一个事务,如果有事务,就把当前事务挂起
NEVER:必须在非事务中执行,如果没有事务,正常执行,如果有事务,报错
NOT SUPPORTS ,必须在非事务中执行
NESTED:必须在事务中执行,如果没有事务就新建事务,如果有事务就嵌套一个事务
事务隔离(ioslation):
在多线程并发访问下保证访问到数据是对的
1脏读 一个事务(a)读取到了一个事务(b)中未提交的数据,另一个事务可能进行了改变,那此时,a读取到的数据就可能和数据库中的数据可能是不一致的,此时认为数据是脏数据.
2不可重复读
主要针对的某一行(列)数据,, 主要针对的是修改数据,不可重复读
两次读在用一个事务内
当事务a读取到的数据,事务b进行了修改,此时,事务a读取到的不一致,此过程不可读
解决问题:限制某一列
3,幻读,
主要针对的操作是新增,或者删除,他是两次事务的结果
事务a按照特定的条件查询出结果,事务b新增了一条符合条件的数据,a查询到的数据和数据库中的数据不一致,a事务好像出现了幻觉
ioslation有五个属性值,分别解决不同的问题
DEFAULT:有底层数据自动判断,使用什么隔离级别
READ_UNCOMMITTED:可以读取未提交数据,可能出现脏读,不可重复读,, 效率最高
READ_COMMITTED 只能读取其他已提交数据,防止脏读,可能出现重复读
REPEATABLE_READ,读取到的数据会被添加锁,防止其他事务修改此事务,防止脏读,重复读,可能出现幻读
SERIALIZABLE,排队操作,对整个表添加锁,一个事务在操作时,另一个事务等到(最安全的)