事务概念
1.什么是事务
1.事务是数据库操作的单元,指在逻辑上的一组操作,要么都成功要么都失败
2.典型场景:银行转账
2.事务的特性(ACID特性)
1.原子性:一个过程不可分割,要么都成功要么都失败
2.一致性:一个数据操作之前与操作之后的总量是不变的
3.持久性:在多事务操作的时候它们之间不会产生影响
4.隔离性:事务提交之后表中的数据也相应的发生了变化
事务操作
搭建事务操作环境
1.创建数据库的表,添加记录
2.创建service,搭建dao,完成对象创建和注入关系
1.在service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
3.在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
@Repositorypublic class UserDaoImpl implements UserDao {@Resourceprivate JdbcTemplate jdbcTemplate;//多钱public void addMoney() {String sql = "update t_account set money=money+? where id=?";jdbcTemplate.update(sql,100,"2");}//少钱 lucy转账100给marypublic void reduceMoney() {String sql = "update t_account set money=money-? where id=?";jdbcTemplate.update(sql,100,"1");}}
service中一个方法
@Servicepublic class UserServiceImpl implements UserService {@Resourceprivate UserDao userDao;//转账public void accountMoney() {//lucy少100userDao.reduceMoney();//mary加100userDao.addMoney();}}
4.上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现了异常,就会有问题
@Servicepublic class UserServiceImpl implements UserService {@Resourceprivate UserDao userDao;//转账public void accountMoney() {//lucy少100userDao.reduceMoney();//模拟异常int i = 1 / 0;//mary加100userDao.addMoney();}}
1.上面的问题该如何解决呢?
使用事务进行解决
@Servicepublic class UserServiceImpl implements UserService {@Resourceprivate UserDao userDao;//转账public void accountMoney() {try{//第一步 开启事务//第二步 进行业务操作//lucy少100userDao.reduceMoney();//模拟异常int i = 1 / 0;//mary加100userDao.addMoney();//第三步 没有发生异常 提交事务}catch (Exception e){//第四步 如果出现异常 事务回滚e.printStackTrace();}}}
Spring事务管理介绍
1.事务添加到javaEE三层结构里面的service层(业务逻辑层)
2.在Spring进行事务管理操作
1.有两种方式
(1)编程式事务管理
(2)声明式事务管理(常用)
3.声明式事务管理
1.基于注解方式
2.基于xml配置文件方式
4.在spring进行声明式事务管理,底层使用AOP原理
5.Spring事务管理API
1.提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
注解声明式事务管理
1.在spring的配置文件中配置事务管理器
<!--创建事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"/></bean>
2.在spring配置文件中,开启事务注解
1.在spring配置文件
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd事务: http://www.springframework.org/schema/tx事务:http://www.springframework.org/schema/tx/spring-tx.xsd">
2.开启事务的注解
<!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
因为spring的事务注解底层是aop实现的所以要把aop配置打开
<!--配置aop--><aop:config proxy-target-class="true"></aop:config>
3.在service类上面(或者service类里面的方法上面)添加一个事务的注解
1.@Transactional,这个注解添加到类上面,也可以添加到方法上面
2.如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
3.如果把这个注解添加到方法上面,为这个方法添加了事务
@Service@Transactionalpublic class UserServiceImpl implements UserService {
声明式事务管理参数配置
1.在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
1.propagation:事务传播行为
1.多事务方法直接进行调用,这个过程中事务是如何进行管理的
Spring框架事务传播行为有7种
前两个必须知道
| REQUIRED | 如果add方法本身就有事务,调用update之后,update使用当前add方法里面的事务. 如果add方法本身没有事务,调用update方法之后,创建一个新的事务 |
|---|---|
| REQUIRES_NEW | 使用add方法去调用update方法,如果add无论是否有事务,都会创建一个新的事务 |
@Service@Transactional(propagation = Propagation.REQUIRED)public class UserServiceImpl implements UserService {
2.isolation:事务的隔离级别
1.事务有特性成为隔离性,多事务操作之间不会产生影响.不考虑隔离性会产生很多问题
2.有三个读问题:脏读,不可重复读,幻读
脏读:一个未提交事务读取到另一个未提交事务的数据
不可重复读:一个未提交事务读取到另一个已经提交事务的修改数据
幻读:一个未提交的事务读取到另一个已提交事务添加的数据
通过设置事务隔离级别可以解决问题
@Service@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE)public class UserServiceImpl implements UserService {
3.timeout:超时时间
1.事务需要在一定的时间内进行提交,如果不提交就会进行回滚
2.默认值为-1,设置时间是以秒为单位进行计算的
@Service@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE,timeout = 5)public class UserServiceImpl implements UserService {
4.readOnly:是否只读
1.读:查询操作,写:添加修改删除操作
2.readOnly默认值为false,表示可以查询,可以添加修改删除操作
3.可以设置readOnly值为true,设置成true之后,只能查询
@Service@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE,timeout = 5,readOnly = false)public class UserServiceImpl implements UserService {
5.rollbackFor:回滚
6.noRollbackFor:不回滚
XML声明式事务管理
1.在spring配置文件中进行配置
1.配置事务管理器
2.配置通知
3.配置切入点和切面
<!--创建事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"/></bean><!--配置通知--><tx:advice id="txadvice"><!--配置事务参数--><tx:attributes><!--指定哪种规则的方法上面添加事务--><!--<tx:method name="accountMoney"/>--><tx:method name="account*" propagation="REQUIRED"/></tx:attributes></tx:advice><!--配置切入点和切面--><aop:config proxy-target-class="true"><!--配置切入点--><aop:pointcut id="pt" expression="execution(* com.ranin.service.impl.UserServiceImpl.*(..))"/><!--配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pt"/></aop:config>
完全注解声明式事务管理
1.创建配置类,使用配置类替代xml配置文件
@Configuration//配置类@ComponentScan(basePackages = "com.ranin")//组件扫描@EnableTransactionManagement//开启事务public class TxConfig {//配置数据库连接池@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.cj.jadb.Driver");dataSource.setUrl("jdbc:mysql://47.93.182.140:3306/test?serverTimezone=GMT%2B8&useSSL=false");dataSource.setUsername("root");dataSource.setPassword("123456");return dataSource;}//创建JdbcTemplate对象@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();//注入datasourcejdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//创建事务管理器@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}}
