事务:逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败
特性:ACID
原子性:不能再次分割
一致性:事务之前与之后,数据保持一致
隔离性:多个事务之间相互隔离,不受影响
持久性:一旦提交后不可恢复
作用:执行增删改时,保持数据的一致、安全,不会像无事务那样出错了仍然提交
Spring的配置事务方式:声明式事务处理、注解方式的声明式事务管理
1.声明式事务处理
(1).在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
https://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">
(2).配置事务管理器
<!-- 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
(3).配置事务通知
<!-- 配置事务通知-->
<tx:advice id="Advice" transaction-manager="transactionManager">
<!-- 配置事务属性,即哪些方法要执行事务-->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/> <!-- 所有insert开头的方法,以下同理 -->
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
(4).配置事务切面
<!-- 配置事务切面-->
<aop:config>
<aop:pointcut id="AdviceAop" expression="execution(* com.wanshi.service..*(..))"/> <!--要执行的方法在哪个包,意思为:com.wanshi.service下的所有包里面的包含任意参数的所有方法-->
<aop:advisor advice-ref="Advice" pointcut-ref="AdviceAop"/> <!-- 配置为AdviceAop执行哪个事务通知 -->
</aop:config>
完整application.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
default-lazy-init="true"
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 https://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:component-scan base-package="com.wanshi"/> <!--包扫描位置-->
<context:property-placeholder location="classpath:db.properties"/>
<!--一下信息皆是为mapper的映射文件实例化所做的操作-->
<!--数据库信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClass}" />
<property name="url" value="${jdbcUrl}" /> <!--记得连接自己的数据库-->
<property name="username" value="${user}" />
<property name="password" value="${password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--sqlSessionFoctory工厂类,用于生产sqlsession对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis的配置文件-->
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<!--配置dao接口扫描包,动态的实现了dao接口可以注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--受扫描的dao包-->
<property name="basePackage" value="com.wanshi.dao"/>
</bean>
<!--将userService交由Spring管理,创建时注入userMapper参数-->
<bean id="userService" class="com.wanshi.service.impl.userService_Impl" scope="singleton">
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务通知-->
<tx:advice id="Advice" transaction-manager="transactionManager">
<!-- 配置事务属性,即哪些方法要执行事务-->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/> <!-- 所有insert开头的方法,以下同理 -->
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切面-->
<aop:config>
<aop:pointcut id="AdviceAop" expression="execution(* com.wanshi.service..*(..))"/> <!--要执行的方法在哪个包,意思为:com.wanshi.service下的所有包里面的包含任意参数的所有方法-->
<aop:advisor advice-ref="Advice" pointcut-ref="AdviceAop"/> <!-- 配置为AdviceAop执行哪个事务通知 -->
</aop:config>
</beans>
接下来我们执行service包下的增删改(insert、delete、update开头)的方法时,就开启事务了
2.注解方式的声明式事务管理
只需要配置事务管理器与注解式事务管理,并且在要开启事务的方法上加上注解: @Transactional
application.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
default-lazy-init="true"
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 https://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:component-scan base-package="com.wanshi"/> <!--包扫描位置-->
<context:property-placeholder location="classpath:db.properties"/>
<!--一下信息皆是为mapper的映射文件实例化所做的操作-->
<!--数据库信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClass}" />
<property name="url" value="${jdbcUrl}" /> <!--记得连接自己的数据库-->
<property name="username" value="${user}" />
<property name="password" value="${password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--sqlSessionFoctory工厂类,用于生产sqlsession对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis的配置文件-->
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<!--配置dao接口扫描包,动态的实现了dao接口可以注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--受扫描的dao包-->
<property name="basePackage" value="com.wanshi.dao"/>
</bean>
<!--将userService交由Spring管理,创建时注入userMapper参数-->
<bean id="userService" class="com.wanshi.service.impl.userService_Impl" scope="singleton">
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注解式事务声明配置-->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
service类代码:
@Transactional //开启事务,抛出异常后就不会再提交了
@Override
public int insert(user record) {
未开启事务前,你的执行增删改sql语句的方法报错后,仍然会commit,开启后,只要抛出异常,就直接rollback