事务
1.是什么事务
事务是数据库操作最基本单元,
典型案例: 银行转账
2.事务四个特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
声明式事务管理
- 基于注解方式
- 基于XML配置文件方式
在spring进行声明式事务管理,底层使用AOP原理
Spring事务管理API
1.提供一个接口代表事务管理器,这个接口针对不容的框架提供不同的实现类.
**事务操作(声明式事务)**你
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:不回滚
设置出来哪些异常不进行回滚
步骤
- Spring配置文件中引入依赖(
数据库引擎需要设置:InnoDB
)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${cqw.driverClassName}"></property>
<property name="url" value="${cqw.url}"></property>
<property name="username" value="${cqw.userName}"></property>
<property name="password" value="${cqw.password}"></property>
</bean>
<!-- 将数据库放入事务管理器中-->
<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>
- Service业务逻辑曾模拟
@Component
//在该类上的所有方法进行事务管理Transactional
@Transactional
public class BookService {
public void BlankAccount() {
bookDao.BlankAccountReduce();
int i = 10 / 0;//模拟事务进行中异常情况
bookDao.BlankAccountAdd();
}
}
- 持久层Dao接口
@Component
public interface BookDao {
void BlankAccountAdd();
void BlankAccountReduce();
}
- 持久层实现类
@Component
public class BookDaoImpl implements BookDao{
@Override
public void BlankAccountAdd() {
String sql="update account set money=money+100 where name= ?";
Object[] objects={"sm"};
int update=jdbcTemplate1.update(sql,objects);
System.out.println("sm得到100元"+update);
return;
}
@Override
public void BlankAccountReduce(){
String sql="update account set money=money-100 where name= ?";
Object[] objects={"cqw"};
int update=jdbcTemplate1.update(sql,objects);
System.out.println("cqw给100元给sm"+update);
return;
}
}
- 测试类
public class TestDemo {
@Test
public void Test4() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/company/bean2.xml");
BookService userAop = (BookService) context.getBean("bookService");
userAop.BlankAccount();
}
}
事务操作(XML声明式事务管理)
在Spring配置文件(XML)中进行配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${cqw.driverClassName}"></property>
<property name="url" value="${cqw.url}"></property>
<property name="username" value="${cqw.userName}"></property>
<property name="password" value="${cqw.password}"></property>
</bean>
<bean id="JdbcTemplateTest" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="com.company"></context:component-scan>
<!-- 引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置通知-->
<tx:advice id="txAdvice">
<!-- 2.配置事务参数-->
<tx:attributes>
<!-- 指定那种规则的方法上面添加事务-->
<tx:method name="bookService" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 3.配置切入点切面-->
<aop:config>
<!-- 切点-->
<aop:pointcut id="pt" expression="execution(* com.company.service.BookService.*(..))"/>
<!-- 切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
</aop:config>
</beans>
事务操作(完全注解声明式事务管理)
完全注解声明式事务管理
- 配置类
package com.company.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.context.annotation.EnableAspectJAutoProxy;
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.company"})
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class Config {
//创建数据库连接对象
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test3");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建JdbcTemple对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransaction = new DataSourceTransactionManager();
dataSourceTransaction.setDataSource(dataSource);
return dataSourceTransaction;
}
}
- 测试类(业务类和上面一样的)
public class TestDemo {
@Test
public void Test6(){
ApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
BookService userAop= (BookService) context.getBean("bookService");
userAop.BlankAccount();
}
}