事务是数据库管理系统中的一个重要概念,它是由一组操作组成的逻辑单元,这些操作要么全部成功执行,要么全部回滚到初始状态,以确保数据的一致性和完整性。
事务的隔离级别是指多个并发事务之间的相互影响程度。
隔离级别定义了一个事务在读取或修改数据时,能否看到其他事务对同一数据所做的更改,以及能否被其他事务看到自己所做的未提交更改。
关系型数据库中定义了四个标准的隔离级别,每个级别提供了不同的数据一致性和并发性能之间的权衡:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ-UNCOMMITTED | ✔ | ✔ | ✔ |
| READ-COMMITTED | × | ✔ | ✔ |
| REPEATABLE-READ | × | × | ✔ |
| SERIALIZABLE | × | × | × |
Spring框架提供了全面的事务管理支持,使得在应用中使用事务变得更加简单和灵活。Spring的事务管理支持主要通过以下几个关键组件来实现:
事务注解(Transaction Annotation)是Spring框架中用于声明式事务管理的一种方式。通过在方法或类上添加@Transactional注解,可以指定方法或类的事务属性,从而实现对方法或类的事务管理。
使用事务注解可以简化事务管理的配置,使得开发者可以通过注解的方式来定义事务的行为,而无需显式编写事务管理的代码。
首先应在全局配置文件,如applicationContext.xml中配置事务管理器并开启注解事务
<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: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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///mybatis">property>
<property name="username" value="root">property>
<property name="password" value="123456">property>
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<context:component-scan base-package="com.yy">context:component-scan>
<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>
配置完成后可在方法或类上利用事务注解来进行声明式事务管理
public class BankService {
//@Autowired
private BankDao bankDao;
public BankDao getBankDao() {
return bankDao;
}
public void setBankDao(BankDao bankDao) {
this.bankDao = bankDao;
}
//利用事务注解来进行事务管理
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 1,readOnly = false,rollbackFor = Exception.class)
public void countMoney(){
bankDao.addMoney();
System.out.println("------");
bankDao.reduceMoney();
}
}
注意:一般情况下,事务注解(Transaction Annotation)会被应用在Service层。
这是因为Service层通常是应用程序的业务逻辑层,包含了多个DAO层的方法调用,需要确保整个Service方法的执行是一个原子操作,确保这些操作要么全部成功,要么全部回滚。这样可以避免数据不一致的问题,提高系统的稳定性和可靠性。
事务切面(Transaction Aspect)是Spring框架中用于实现声明式事务的关键组件之一。
它通过AOP(Aspect-Oriented Programming)的方式将事务逻辑织入到业务逻辑中,实现了事务的管理与业务逻辑的解耦。
首先应在全局配置文件,如applicationContext.xml中配置事务管理器并配置通知,切面与切入点
<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: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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///mybatis">property>
<property name="username" value="root">property>
<property name="password" value="123456">property>
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<context:component-scan base-package="com.yy">context:component-scan>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="txadvice">
<tx:attributes>
<tx:method name="countMoney" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="p" expression="execution(* com.yy.service.BankService.countMoney(..))" />
<aop:advisor advice-ref="txadvice" pointcut-ref="p">aop:advisor>
aop:config>
<bean id="bankDaoImpl" class="com.yy.dao.impl.BankDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate">property>
bean>
<bean id="bankService" class="com.yy.service.BankService">
<property name="bankDao" ref="bankDaoImpl">property>
bean>
beans>
此时,只需在service层使用对应方法即可
public class BankService {
//@Autowired
private BankDao bankDao;
public BankDao getBankDao() {
return bankDao;
}
public void setBankDao(BankDao bankDao) {
this.bankDao = bankDao;
}
//由于在全局配置文件中使用了事务切面,这里就无需使用事务注解来进行事务管理了
//@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 1,readOnly = false,rollbackFor = Exception.class)
public void countMoney(){
bankDao.addMoney();
System.out.println("------");
bankDao.reduceMoney();
}
}