事务

简介

事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元);

事务的四个特征

  1. 原子性 : 事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做
  2. 一致性 : 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
  3. 隔离性: 一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持续性 : 也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

事务的隔离级别

事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡

  1. DEFAULT
    默认隔离级别,每种数据库支持的事务隔离级别不一样,如果Spring配置事务时将isolation设置为这个值的话,那么将使用底层数据库的默认事务隔离级别。顺便说一句,如果使用的MySQL,可以使用"select @@tx_isolation"来查看默认的事务隔离级别

  2. READ_UNCOMMITTED
    读未提交,即能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用

  3. READ_COMMITED
    读已提交,即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读

  4. REPEATABLE_READ
    重复读取,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决

  5. SERLALIZABLE
    串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了

脏读、幻读、不可重复读

  1. 脏读(dirty read):事务A读到了事务B还没有提交的数据。
时间取款事物存款事物
T1开始事物
T2开始事物
T3查询账户余额为1000元
T4汇入100元把余额改为1100元
T5查询账户余额为1100元(读取脏数据)
T6回滚
T7取款1100
T8提交事物失败
  1. 幻读( phantom read ):在一个事务里面的操作中发现了未被操作的数据。
时间查询学生事物插入新学生事物
T1开始事物
T2开始事物
T3查询学生为10人
T4插入一个新学生
T5查询学生为11人
T6提交事物
T7提交事物
  1. 不可重复读(non-repeatable read):在一个事务里面读取了两次某个数据,读出来的数据不一致。
时间取款事物存款事物
T1开始事物
T2开始事物
T3查询账户余额为1000元
T4汇入100元把余额改为1100元
T5提交事物
T6查询账户余额为1100元(读取脏数据)
T8提交事物

第一类丢失更新(lest update)

时间取款事物存款事物
T1开始事物
T2开始事物
T3查询账户余额为1000元
T4查询账户余额为1000元
T5汇入100元把余额改为1100元
T6提交事物
T7取出100元把余额改为900元
T8撤销事物
T9余额恢复为1000元(丢失更新)

第二类丢失更新(Second lost update problem)【不可重复读的特殊情况】

时间转账事物取款事物
T1开始事物
T2开始事物
T3查询账户余额为1000元
T4查询账户余额为1000元
T5取100元把余额改为900元
T6提交事物
T7汇入100元
T8提交事物
T9把余额改成1100元(丢失更新)

在这里插入图片描述

Spring-tx

1、导入maven依赖

	<!--Spring-webmvc  -->
	<!-- mysql -->
	<!-- spring-tx -->	
	<!-- aspectj -->	
	<!-- jdbc -->
	<!-- dbcp -->

2、创建实体类

private int id;
private double money;

3、添加数据访问层

@Repository
public class UserDaoImpl implements UserDao{
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	//操作数据库完成数据查找
	public double select(int id) {
		// TODO Auto-generated method stub
		return jdbcTemplate.queryForObject("select money from t_u where id = ?",Integer.class,id);
	}
	//操作数据库完成数据更新
	public void update(int id, double money) {
		// TODO Auto-generated method stub
		jdbcTemplate.update("update t_u set money = ? where id = ?", new Object[]{money ,id});
	}
}

4、添加数据业务层

@Service
public class UserServiceImpl {
	@Autowired
	private UserDao userDao;
	
	public void transfer(int fromId, int toId, double money) {
		double money1=userDao.select(fromId);
		userDao.update(fromId, money1-money);	
		double money2=userDao.select(toId);
		userDao.update(toId, money2+money);
	}
}

5、配置文件config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:context="http://www.springframework.org/schema/context" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
	<!-- 扫描注解 -->
	<context:annotation-config/>
	<context:component-scan base-package="spring"></context:component-scan>
	<!-- 导入资源文件 -->
	<context:property-placeholder location="jdbc.properties"/>
	<!--  数据源-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${d}"></property>
		<property name="url" value="${url}"></property>
		<property name="username" value="${u}"></property>
		<property name="password" value="${p}"></property>
	</bean>
	<!-- 配置事务管理器e -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- aop  -->
	<bean id="userService" class="spring.service.UserServiceImpl"></bean>
	<aop:config>
		<aop:pointcut expression="execution(* spring.service.*.*(..))" id="cut"/>
		<aop:advisor advice-ref="tx" pointcut-ref="cut"/>
	</aop:config>
	
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- tx -->
	<tx:advice id="tx" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>
</beans>

6、测试类

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext context =new ClassPathXmlApplicationContext("config.xml");
		UserServiceImpl service = context.getBean("userService",UserServiceImpl.class);
		service.transfer(1, 2, 200);
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值