目录
补充:(5.26)
首先要明白,为什么要事务管理?
当你数据出现异常情况时,可以保证数据的一致性—>正确就数据发生改变,否则数据回滚;
事务管理方式:
Spring有两种事务管理方式:编程式事务管理+声明式事务管理;
编程式事务:使用TransactionTemplate或者使用PlatformTransactionManager;
声明式事务:建立在AOP之上,本质是对方法的前后进行拦截—>在目标方法之前或者之后加入一个事务(目的就是根据目标方法执行的情况决定是否回滚事务)
好处:声明式事务的话就不需要再业务逻辑代码中加一些掺杂事务管理的代码,业务逻辑代码不受到其他代码的污染;
对比:编程式事务可以作用到整个代码块级别,而声明式事务只能作用到方法级别;
—>只需要在配置文件中做相关事务的规则声明;
—>事务整合到业务逻辑中(基于@Transactional注解的方式)—>(或者是基于tx和aop命名空间的xml配置文件);
Spring事务回滚规则:
Spring只有在抛出异常为unchecked异常时才能回滚该事务,如果是checked异常则不会导致事务回滚,
@Transactional:
可以标注在任何地方上,但是标注在实现类上是最好的,因为注解是不能继承的;
事务的使用:
Spring配置文件中进行添加:1.首先声明数据源支持事务;2.采用声明事务;
<bean id="transcationManager" class="org.springframework.jdbc.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--使用声明式事务,引用上面的事务管理器--> <tx:annotation-driven transaction-manager="transactionManager"/>
使用:在ServiceImp类上使用@Transactional注解即可;
再细节一点的配置文件配置:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--开启注解模式--> <context:annotation-config /> <!-- 数据库连接池 --> <!-- 加载配置文件 --> <context:property-placeholder location="classpath:properties/jdbc.properties"/> <!-- 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="driverClassName" value="${jdbc.driver}"/> <property name="maxActive" value="10"/> <property name="minIdle" value="5"/> </bean> <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据库连接池 --> <property name="dataSource" ref="dataSource"/> <!-- 加载mybatis的全局配置文件 --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/> </bean> <!--配置mapper扫描包--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.lnp.mapper"/> </bean> <!--==========================以上内容为applicationContext-dao配置===================================--> <!--自动扫描service--> <context:component-scan base-package="com.lnp.service" /> <!-- 事务管理器 --> <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="save*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 切面 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lnp.service.*.*(..))" /> </aop:config> <!--==========================以上内容为applicationContext-service配置============================--> </beans>
我的话反正喜欢用注解:
然后我们来说一说数据库事务的几个特性:
Isolation(隔离性):数据库允许多个并发事件同时对数据进行操作,这个同时是一个时间片段的同时,而隔离性就是保证各个事务相互独立,事务处理的中间状态->其他事务是不可见的,以此防止出现数据不一致的状态;
Durable(持久性):一个事务处理完后,对数据库的修改是永久性的,就算是系统故障也不会丢失数据;
原子性:事务中的操作要么都做要么都不做;
一致性:事务处理的结果必须是使数据库从一个一致性的状态到另一个一致性的状态;
事务可以理解为一件事情,这个事情里面可以有多个操作,是一系列操作(要么都执行要么都不执行-原子性特点)->事务是一组不可分割的操作集合;
设置事务隔离级别:
@Transactional(isolation=isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读与不可重复读);
@Transactional(isolatio=isolatio.READ_COMMITTED):读取已经提交的数据(会出现不可重复读与幻读);
@Transactional(isolation=isolation.REPEATABLE_READ):会出现幻读;
@Transactional(isolation=isolation.SERLALIZABLE):串行化
mysql默认是REPEATABLE_READ;
事务:
脏读:两个事务并发执行时(并发就是一个cpu将一个时间片段分给了多个线程,所以多线程说不是同时间执行的)—>也就是说一个事务访问到了另外一个事务未提交的数据(比如说一个cpu给两个事务给了4:6的时间,然后事务1对数据库进行了修改,此时立马到事务2了,然后一读取数据,因为事务1未提交,所以事务2读取的就是修改之前的数据);->感悟:如果两个事务,第一个事务查询未提交。第二个事务将数据修改提交,然后cpu再给到第一个事务,第一个事务一提交那岂不是查到的数据和预想的就不一样了
不可重复读:一个事务查询同一条记录两次,得到的结果不一致;
比如:事务1开始查询,然后事务2修改数据提交事务,事务1再查就发现数据不一样了;
张三需要转正1000元,系统读到卡余额有2000元,此时张三老婆正好需要转正2000元,并且在张三提交事务前把2000元转走了,当张三提交转账是系统提示余额不足
幻读:
一个事务查询两次,得到的记录条数不一致—>事务1查询数据,事务2插入数据并且提交->然后事务1再次查询数据并且提交—>发现得到的记录条数不一致;
张三老婆准备打印张三这个月的信用卡消费记录,经查询发现消费了两次共1000元,而这时张三刚按摩完准备结账,消费了1000元,这时银行记录新增了一条1000元的消费记录。当张三老婆将消费记录打印出来时,发现总额变为了2000元,这让张三老婆很诧异。
具体例子:
(10条消息) Spring事务和MySQL事务详解面试_好好学习天天向上-CSDN博客_spring事务与mysql事务区别