事务
什么是事务?
-
事务是数据库操作最基本单元,逻辑上一组操作 ,要么都成功,如果有一个失败那么所有操作都会失败
-
典型场景:银行转账
Lucy转账100给 Mary
Lucy少100,Mary多100
事务的四大特性--ACID
-
原子性
-
一致性
-
隔离性
-
持久性
环境的搭建
接下来我们使用最为传统的转账的情况下进行搭建
1.通过在数据库进行添加两条表记录
INSERT INTO t_user(username, money) VALUES('Lucy', 1000),('Mary', 1000);
2.创建上图的service,dao,以及dao的实现类daoImpl,创建完成之后进行在service中注入dao,在dao中注入JdbcTemplate,在JdbcTemplate中注入dataSource
<!--开启组件扫描--> <context:component-scan base-package="com.xuan"/> <!--数据库连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql:///guigu_bookdb" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"/> </bean>
3.进行创建一个测试类进行测试
@Test public void t1(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); UserService userService = context.getBean("userService", UserService.class); userService.accountTest(); }
上面就是基本的环境搭建
而我们既然运用转账的这个例子那么就是要去引出问题,加入转账的时候一方的网络出现问题,此时代码就会出现异常,此时就需要去运用事务来进行解决。
出现异常的代码如下 :
public void accountTest(){ // Lucy 给 Mary 转 100 userDao.reduceMoney(); // 模拟网络异常 int i = 1/0; // Mary 收到 Lucy 的 100 userDao.addMoney(); }
初步的解决方案;
而这种解决方案是不是看起来非常的繁琐呢,其实接下来我们要学习的关于事务的操作才是本文的重点,请继续往下面看。
Spring事务管理介绍
在javaEE的三层结构之中,我们关于事务的操作一般看成一种处理问题的解决方案,这个一般都写在Service层(业务逻辑层);
在spring中的事务管理操作,一般的话会有两种方式:
-
编程式的事务管理,就是上面我说的比较复杂的方式进行事务管理
-
声明式事务管理(重点)
声明式事务管理:
-
基于注解的方式
-
基于配置文件的方式(XML)
这里进行补充一下,在Spring中实现声明式事务管理的底层使用了AOP原理
Spring事务管理API,这个API提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类。
声明式事务管理(注解)
-
在Spring配置文件中配置事务管理器;
<!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"/> </bean>
-
在配置文件中开启事务注解;
引入名称空间:
开启事务注解:
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
在Service类上面(或者Service类里面的方法上)添加事务注解;
-
@Transactional,这个注解可以添加到类上面,也可以添加到方法上面;
-
如果把这个注解添加类上面,则这个类里面所有的方法都会被添加事务;
-
如果把这个注解添加方法上面,则这个方法会被添加事务;
@Service @Transactional // 使用声明式注解 public class UserService {}
-
声明式事务管理参数配置
在Service类上面添加注解@Transactional,在这个注解里面可以配置相关的参数。
1. propagation:事务传播行为,当一个事务的方法被另外一个事务的方法调用时候,这个事务方法如何进行 。
REQUIRED:
REQUIRED_NEW:
SUPPORTS:
@Transactional(propagation = Propagation.REQUIRED) 1
2. ioslation: 事务隔离级别
事务中有一个特性,这个特性交隔离级别,多事务操作之间不会产生影响。如果不考虑事务的隔离性,则会产生很多的问题。主要有三大问题:
-
脏读:一个未提交事务读取到另一个未提交事务的数据,通常都与事务的回滚有关;
-
不可重复读:一个未提交事务读取到另一提交事务修改的数据;
-
幻读;一个未提交事务读取到另一提交事务添加的数据;
通过设置事务的隔离级别可以解决以上的问题。
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
READ UNCOMMITTED(读未提交) | 有 | 有 | 有 |
READ COMMITTED(读已提交) | 无 | 有 | 有 |
REPEATABLE READ(可重复读) | 无 | 无 | 有 |
SERIALIABLE(串行化) | 无 | 无 | 无 |
@Transactional(isolation = Isolation.READ_COMMITTED) 1
3. timeout: 超时时间
事务需要在一定的时间内进行提交,如果不提交该事务则会回滚。timeout的默认值是 -1 ,设置时间以秒单位进行计算。
5. readOnly: 是否只读
读通常对应于数据库的查询操作,写对应于数据库的添加、修改、删除操作。readOnly 默认值 false,表示可以进行CRUD操作,如果设置 readOnly 值为 true,则只能进行查询。
6. rollbackFor: 回滚
设置当程序出现哪些异常时,进行事务的回滚。
7. noRollbackFor: 不回滚
设置当程序出现哪些异常时,不进行事务的回滚。
在这里XML声明式事务管理我就不写了,这个作为一个了解即可,大部分情况下我们都是采用注解的方式来进行实现声明式事务管理
完全注解实现声明式事务管理
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("com.xuan") // 组件扫描 @EnableTransactionManagement // 开启事务 public class TxConfig { // 创建数据库连接池 @Bean // 这个注解对应于配置文件中的bean标签 public DruidDataSource getDruidDataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///guigu_bookdb"); dataSource.setUsername("root"); dataSource.setPassword("root"); return dataSource; } /** * 创建JdbcTemplate对象 * @param dataSource DataSource源,巧妙思想:直接让Spring到ioc容器中去寻找对应的类型。 * @return JdbcTemplate对象。 */ @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource){ // 到ioc容器中根据类型找到dataSource进行注入 JdbcTemplate jdbcTemplate = new JdbcTemplate(); // 注入dataSource jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } // 创建事务管理器 @Bean public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } }
以上就是关于事务的一些知识了,谢谢你的观看了。