前言
事务是数据库操作最基本单位,要么都成功,要么都失败。
一、事务及其参数含义
1.事务的四个特性
- 原子性
- 一致性
- 隔离性
- 持久性。
2.事务的传播行为(propagation)
Spring定义了7种传播行为:
传播属性 | 描述 |
REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行 |
REQUIRED_NEW | 当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起 |
SUPPORTS | 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 |
NOT_SUPPORTED | 当前方法不应该运行在事务中,如果有运行的事务,将它挂起 |
MANDATORY | 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常 |
NESTED | 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行 |
这里只图解介绍一个,其他类推
3.事务隔离性
- 脏读:一个未提交事务读取到另一个未提交事务的数据
例:事务A读取到事务B修改后的数据,但是读取后事务B回滚了,此时A读取的是修改后的数据,但是修改撤销了。 - 不可重复读:一个未提交的事务读取到另一个提交事务修改数据
例:事务A和事务B读取同一个数据,但是事务B在读取后进行修改,然后提交,提交后事务A又读取这个数据,此时读取的是修改后的,跟上次读取的不一样。 - 幻读(虚读):一个未提交的事务读取到另一个提交事务添加数据
4.事务的隔离级别(ioslation)
5.timeout(超时)
事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。
6.readOnly(是否只读)
读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。
7.rollbackFor(回滚)
设置出现哪些异常进行事务回滚。
8.noRollbackFor(不回滚)
设置出现哪些异常不进行事务回滚。
二、事务管理
Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。
1.事务管理的两种形式:
- 编程式事务管理
例:
try{ //开启事务 //进行业务操作 userDao.reduceMoney(); //模拟异常 int i=10/0; userDao.addMoney(); //没出现异常,事务提交 }catch (Exception e){ //异常,事务回滚 }
- 声明式事务管理(AOP原理)
例:
@Service @Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED) public class UserService{ @Autowired private UserDao userDao; public void accountMoney(){ userDao.reduceMoney(); int i= 1 / 0; userDao.addMoney(); } }
2.注解实现声明式事务管理
就是上述声明式管理的例子,这里补充一下全部代码:
================userDao==================== package com.dragon.shiwu.dao; public interface UserDao { public void addMoney(); public void reduceMoney(); } ==============userDaoImpl=================== package com.dragon.shiwu.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class UserDaoImpl implements UserDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public void addMoney() { String sql="update t_account set money=money + ? where username = ?"; jdbcTemplate.update(sql,100,"mary"); } @Override public void reduceMoney() { String sql="update t_account set money=money-? where username=?"; jdbcTemplate.update(sql,100,"lucy"); } } ==============userService============================ package com.dragon.shiwu.service; import com.dragon.shiwu.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service @Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED) public class UserService{ @Autowired private UserDao userDao; public void accountMoney(){ userDao.reduceMoney(); int i= 1 / 0; userDao.addMoney(); } } ============Spring配置文件===========================(注意这里引入了tx命名空间和) <?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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${pro.driverClass}"></property> <property name="url" value="${pro.url}"></property> <property name="username" value="${pro.username}"></property> <property name="password" value="${pro.password}"></property> </bean> <!--创建JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入数据库连接池--> <property name="dataSource" ref="dataSource"></property> </bean> <context:component-scan base-package="com.dragon.shiwu"></context:component-scan> <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>
运行前:
运行后:
3.xml实现声明式事务管理
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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${pro.driverClass}"></property> <property name="url" value="${pro.url}"></property> <property name="username" value="${pro.username}"></property> <property name="password" value="${pro.password}"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启组件扫描--> <context:component-scan base-package="com.dragon.shiwu"></context:component-scan> <!--配置事务通知--> <tx:advice id="txadvice"> <tx:attributes> <!--配置事务参数--> <tx:method name="accountMoney" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 配置切入点和切面--> <aop:config> <!-- 配置切入点--> <aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/> <!-- 配置切面--> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor> </aop:config> </beans>
4.完全注解开发
TxConfig类:
package com.dragon.shiwu.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; @Configuration//配置类 @ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描 @EnableTransactionManagement//开启事务 public class TxConfig { //创建数据库连接池 @Bean public DruidDataSource getDruidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db"); druidDataSource.setUsername("root"); druidDataSource.setPassword("root"); return druidDataSource; } //创建JdbcTemplate对象 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } //创建事务管理器 @Bean public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } }
测试类:
package com.dragon.shiwu.test; import com.dragon.shiwu.config.TxConfig; import com.dragon.shiwu.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class test2 { public static void main(String[] args) { ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class); UserService userService = context.getBean("userService",UserService.class); userService.accountMoney(); } }
总结
以上就是Spring事务管理的讲解。