事务
1.是什么事务
事务是数据库操作最基本单元,
典型案例: 银行转账
2.事务四个特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
声明式事务管理
- 基于注解方式
- 基于XML配置文件方式
在spring进行声明式事务管理,底层使用AOP原理
事务操作(声明式事务)
@Transactional参数讲解
- Propagation:传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
- ioslation:事务隔离
名称 | 描述 |
---|---|
脏读 | 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。 |
不可重复读 | 事务 A 多次读取同一数据, 中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。 |
幻读 | 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。 |
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
- timeout:超时事件
事务在一定时间内进行提交,如果不提交进行回滚
默认值是-1,设置时间以秒为单位进行计算
- readOnly:是否只读
默认false,表示可以查询也可以新增修改删除
- rollbackFor:回滚
设置出现哪些异常进行事务回滚
- noRollbackFor:不回滚
设置出来哪些异常不进行回滚
相关代码
1.配置文件
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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/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">
<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test3"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"></property>
</bean>
<!-- 注解扫描-->
<context:component-scan base-package="com.company.Tx"></context:component-scan>
<!-- 创建事务管理器-->
<bean id="Transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>
</bean>
<bean id="sMDao" class="com.company.Tx.Dao.SMDao" abstract="true"></bean>
<bean id="sMDaoImpl" class="com.company.Tx.Dao.SMDaoImpl" autowire="byType"></bean>
<bean id="sMService" class="com.company.Tx.Service.SMService" autowire="byType"></bean>
<!--配置通知-->
<tx:advice id="cqw" transaction-manager="Transaction">
<tx:attributes>
<tx:method name="playMoney" propagation="REQUIRED" isolation="REPEATABLE_READ"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.company.Tx.Service.SMService.*(..))"/>
<!-- 配置切面-->
<aop:advisor advice-ref="cqw" pointcut-ref="pt"></aop:advisor>
</aop:config>
<!-- 开启事务管理器-->
<!-- <tx:annotation-driven transaction-manager="Transaction"></tx:annotation-driven>-->
</beans>
2.相关Dao、Service操作类
- SMDao
package com.company.Tx.Dao;
public interface SMDao {
public void add();
public void reduce();
}
- SMDaoImpl
package com.company.Tx.Dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
public class SMDaoImpl implements SMDao{
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public void add() {
String sqlAdd="update account set money=money-100 where name=?";
Object[] objects={"cqw"};
final int update = jdbcTemplate.update(sqlAdd, objects);
System.out.println("cqw少了100元的结果::"+update);
}
@Override
public void reduce() {
String sqlAdd="update account set money=money+100 where name=?";
Object[] objects={"sm"};
final int update = jdbcTemplate.update(sqlAdd, objects);
System.out.println("SM得到100元的结果::"+update);
}
}
- SMService
package com.company.Tx.Service;
import com.company.Tx.Dao.SMDao;
public class SMService {
private SMDao sMDao;
public void setsMDao(SMDao sMDao) {
this.sMDao = sMDao;
}
public void playMoney(){
sMDao.add();
int a=10/0;
sMDao.reduce();
}
}
- TestDemo
@Test
public void Test06(){
ApplicationContext context = new ClassPathXmlApplicationContext("com/company/beanTX.xml");
final SMService sMService = context.getBean("sMService", SMService.class);
sMService.playMoney();
}
- Result (数据回滚,数据不变)
cqw少了100元的结果::1
java.lang.ArithmeticException: / by zero
at com.company.Tx.Service.SMService.playMoney(SMService.java:21)