spring实现事务管理
事务(Transaction)是面向关系型数据库(RDBMS)企业应用程序的重要组成部分,用来确保数据的完整性和一致性。
- 事务的ACID 特性
原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的动作要么都做要么都不做。
一致性(Consistency):事务必须保证数据库从一个一致性状态变到另一个一致性状态,一致性和原子性是密切相关的。
隔离性(Isolation):一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相打扰。
持久性(Durability):持久性也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就是永久性的,后面的其它操作和故障都不应该对其有任何影响。
- spring事务的传播属性 Propagation
REQUIRED:
使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;如果当前存在事务,则加入这个事务,成为一个整体。
举例:领导没饭吃,我有钱,我会自己买了自己吃;领导有的吃,会分给你一起吃。
SUPPORTS:
如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。
举例:领导没饭吃,我也没饭吃;领导有饭吃,我也有饭吃。
MANDATORY:
该传播属性强制必须存在一个事务,如果不存在,则抛出异常
举例:领导必须管饭,不管饭没饭吃,我就不乐意了,就不干了(抛出异常)
REQUIRES_NEW:
如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;如果当前没有事务,则同 REQUIRED
举例:领导有饭吃,我偏不要,我自己买了自己吃
NOT_SUPPORTED:
如果当前有事务,则把事务挂起,自己不适用事务去运行数据库操作
举例:领导有饭吃,分一点给你,我太忙了,放一边,我不吃
NEVER:
如果当前有事务存在,则抛出异常
举例:领导有饭给你吃,我不想吃,我热爱工作,我抛出异常
NESTED:
如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;如果当前没有事务,则同 REQUIRED。但是如果主事务提交,则会携带子事务一起提交。如果主事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。
举例:领导决策不对,老板怪罪,领导带着小弟一同受罪。小弟出了差错,领导可以推卸责任。
- spring中的事务隔离级别
isolation-default 这是platformTransactionManager默认的事务隔离级别,使用数据库默认的事务隔离级别/另外4个与JDBC的事务隔离级别相对应
isolation-read_uncommitted
isolation-read_committed
isolation-repeatable-read
isolation-serializable
- Spring 的事务管理有 2 种方式:
1)传统的编程式事务管理,即通过编写代码实现的事务管理;
2)基于 AOP 技术实现的声明式事务管理。
本文是用声明式事务管理
- 是什么?
通过 AOP 实现的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
- 优点?
不需要通过编程的方式管理事务,可以将业务逻辑代码和事务管理代码很好的分开。
- 声明式事务管理主要有 2 种方式:
基于 XML 方式的声明式事务管理。
通过 Annotation 注解方式的事务管理。
下面介绍如何通过 XML 的方式实现声明式事务管理
- pom依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--Spring事物依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
- 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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启扫描注解 -->
<context:component-scan base-package="com.ljw"></context:component-scan>
<!-- 引入外部properties文件 -->
<context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
<!-- 通过druid连接池获取数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="${driver}"></property>
<!--连接数据库的url -->
<property name="url" value="${url}"></property>
<!--连接数据库的用户名 -->
<property name="username" value="${user}"></property>
<!--连接数据库的密码 -->
<property name="password" value="${pwd}"></property>
</bean>
<!-- 配置JDBC模板,使用JdbcTemplate类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--默认必须使用数据源 引用上面的数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 编写通知:对事务进行增强(通知),需要编写切入点和具体执行事务的细节 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 给切入点方法添加事务详情,name表示方法名称,*表示任意方法名称,
propagation用于设置传播行为,read-only表示隔离级别,是否只读 -->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- aop编写,让Spring自动对目标生成代理,需要使用AspectJ的表达式 -->
<aop:config proxy-target-class="true">
<!-- 切入点,execution定义的表达式表示com.ljw.service.impl包下的所有类所有方法都应用该事务 -->
<aop:pointcut id="point" expression="execution(* com.ljw.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
</aop:config>
- bean类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
private Integer goodId;
private Integer typeId;
private String goodName;
private Integer goodNum;
private Float goodPrice;
public Goods(Integer typeId, String goodName, Integer goodNum, Float goodPrice) {
this.typeId = typeId;
this.goodName = goodName;
this.goodNum = goodNum;
this.goodPrice = goodPrice;
}
- dao层实现
@Controller
public class GoodsDaoImpl implements GoodsDao {
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public List<Goods> findAll() {
String sql = "select * from goods";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Goods.class));
}
@Override
public Integer save(Goods goods) {
String sql = "INSERT INTO goods VALUES(NULL,?,?,?,?)";
return jdbcTemplate.update(sql,goods.getTypeId(),goods.getGoodName(),goods.getGoodNum(),goods.getGoodPrice());
}
@Override
public Integer update(Goods goods) {
String sql = "UPDATE goods SET type_id=?,good_name=?,good_num=?,good_price=? WHERE good_id=?";
return jdbcTemplate.update(sql,goods.getTypeId(),goods.getGoodName(),goods.getGoodNum(),goods.getGoodPrice(),goods.getGoodId());
}
@Override
public Integer delete(Integer id) {
String sql = "delete from goods where good_id = ?";
return jdbcTemplate.update(sql,id);
}
}
- service层实现
@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
GoodsDao goodsDao;
@Override
public List<Goods> findAll() {
return goodsDao.findAll();
}
@Override
public Integer saveAndUpdate(Goods goods,Goods goods2) {
Integer rows = goodsDao.save(goods);
Integer rows2 = goodsDao.update(goods2);
return rows + rows;
}
@Override
public Integer delete(Integer id) {
return goodsDao.delete(id);
}
}
- 测试
@Test
public void save() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
GoodsService goodsService = context.getBean("goodsServiceImpl", GoodsServiceImpl.class);
//添加的对象
Goods goods = new Goods(3, "test88", 2, 2f);
//修改的对象
Goods goods2 = new Goods(1, 9, "test", 2, 2f);
int rows = goodsService.saveAndUpdate(goods, goods2);
System.out.println(rows);
}
添加和修改的方法要同时成功,否则事务回滚
注解 的方式实现声明式事务管理
- spring–xml文件
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 通过注解加事务 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"></tx:annotation-driven>
- 只用在service层实现中加上注解@Transactional
@Transactional
public class GoodsServiceImpl implements GoodsService {
//towork
}