事务的ACID特性:原子性、 一致性、 隔离性 、持久性。
事务分两种,一种是编程式事务。就是以前我们利用jdbc写的commit和rollback的方式提交或者回滚事物。这种控制事物的方式比较麻烦,一般在做大型项目的时候不建议使用这种方式。
另外一种是声明式事务。声明式事物,就像字面意思说的一样,在一个地方声明一下,然后程序中不需要再由事务控制的代码,使用起来非常简单。
spring是支持声明式事物的,我们只需要在spring的主配置文件中做简单的配置,就可以使用事物。
声明式事物要加到原来开发代码的哪一层。
dao层 持久化层(负责连接数据库,执行数据库的增删改查)
service层 业务逻辑层 (负责实现系统所有的业务逻辑)
controller层 控制层 (接收前台参数,调用service层业务逻辑,往前台返回数据)
保存订单的业务实现:
控制层:负责接收前台传过来的订单信息,订单明细的信息 ,调用业务逻辑层保存订单的方法
业务逻辑层: 写保存订单的方法 保存订单的方法应该先调持久化层保存主订单的方法,再调用持久层保存订单明细的方法
持久化层:保存主订单的方法 保存订单明细的方法
我们不希望出现保存订单的时候 主订单保存成功之后,出现了异常,然后订单明细没有保存成功,如果是这样,数据库中的数据就不完整的了。所以我们一般为了避免这种类似的情况,我们可以把事物加到service层。
利用配置文件的方式配置声明式事务
如果在业务逻辑层保存过一部分数据之后产生异常,我们肯定不希望 异常前面的数据保存成功,而异常后面的数据没有保存,这不复合事物的原子性原则。我们希望save方法中的业务逻辑要么全部成功,要么出异常了全部失败。
<?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/springcontext.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/springaop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--扫描dao接口所在的包--> <context:component-scan base-package="com.aaa.spring.dao.impl,com.aaa.spring.service.impl"> </context:component-scan> <!---创建dbcp数据源连接池对象--> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"></property> <property name="username" value="scott"></property> <property name="password" value="tiger"></property> </bean> <!--创建jdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!---创建spring的事物管理器对象--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!---创建spring事物管理的通知类对象--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!---此处可以配置事物管理的一些特性--> <tx:attributes> <!--- name属性中可以使用通配符,用来指定该属性对哪些方法起作用 propagation 配置事物的传播特性 REQUIRED 判断当前方法是否存在事物,如果不存在事物就创建一个新的事物,如果存在事物就使用当前的事 物 REQUIRES_NEW 判断当前方法是否存在事物 ,如果不存在事物就创建一个新的事物, 如果存在事物,就把当前事物挂起,再启动一个新的事物 NESTED 嵌套事物 。判断当前方法是否存在事物,如果不存在事物就创建一个事物,如果存在事物,把当前事物 挂起, 再启动一个当前事物的子事物 。这样如果父事物产生了异常。子事物即使没有产生异常也会回滚。 read-only 配置事物的只读特性 true 当前事物是只读事物,在方法之后不会提交事物 flase 默认值 当前事物是非只读事物,在方法之后会提交事物 配置事物的只读特性 增删改方法一般需要事物,查询方法一般不需要事物,所以以后开发的时候最好查询方法把 read-only 设置成true,在一定程度上能提高程序的运行效率 --> <tx:method name="save*" propagation="NESTED" /> <tx:method name="select*" propagation="REQUIRED" read-only="true"></tx:method> </tx:attributes> </tx:advice> <!---配置spring的声明式事物--> <aop:config> <!---声明切入点对象 告诉spring 要对哪些类的哪些方法使用事物--> <aop:pointcut id="p1" expression="execution(* com.aaa.spring.service.impl.*.*(..))"></aop:pointcut> <!--声明事物管理专用的切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="p1"></aop:advisor> </aop:config> </beans>
注意:使用spring的事物必须加入以下jar包:
事物什么时候回滚?一定要记住,service方法如果抛出了运行时异常,才会回滚。
使用注解的方式配置声明式事物
第一步,在spring主配置文件中声明以注解的方式配置spring的事物
第二步,要在需要使用事物的类上增加@Transactional注解
比如要在OrderItemServiceImpl类上增加事物:
如果要配置事物的传播特性和只读特性可以在Transactional注解中增加参数:
@Transactional注解不但可以加到类上,也可以加到方法上。
加到方法上事物特性配置优先级高于类上面的。