Spring的事务管理

一.事务的隔离级别和传播行为
1.事务的隔离级别:
默认级别:DEFAULT,属于下面四种级别的某一种

  • 可重复读:REPEATABLE_READ
  • 读未提交:READ_UNCOMMITTED
  • 读已提交:READ_COMMITTED,是oracle数据库默认级别
  • 串行化:SERIALIZABLE

2.事务传播行为:
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式运行
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,抛出异常。

二.事务管理的分类
1.编程式事务管理:在代码中显示调用beginTransaction、commit、rollback等事务处理相关的方法
2.声明式事务管理:通过AOP技术实现。对方法前后进行拦截,在目标方法开始之前创建一个事务,执行完目标方法之后根据执行情况提交或回滚事务。

声明式事务管理更简单方便,有利于后期代码维护

三.声明式事务管理

1.基于XML方式的声明式事务管理
建表:
create table account(
id number primary key,
name varchar2(255),
money number
);
insert into account values(1,‘张三’,1000)
insert into account values(2,‘李四’,300);

使用的jar包:
在这里插入图片描述

实体类:

@Data
public class Account {
	private int id;
	private String name;
	private Double money;
}

数据源文件:dataSource.properties

jdbc.driverClass=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1522:xe
jdbc.username=jy
jdbc.password=jy
initialSize=5
maxActive=10

DAO层接口:

public interface AccountDao {
	//存钱
	void incrementMoney(long id,double money);
	//取钱
	void decrmentMoney(long id,double money);
	//查询所有账户
	void findAll();
}

DAO层实现类:

@Repository
public class AccountDaoImpl implements AccountDao{
	@Autowired
	private JdbcTemplate jdbcTemplate;
	@Override
	public void incrementMoney(long id, double money) {
		String sql ="update account set money = money + ? where id = ?";
		jdbcTemplate.update(sql, money,id);		
	}
	@Override
	public void decrmentMoney(long id, double money) {
		String sql = "update account set money = money - ? where id = ?";
		jdbcTemplate.update(sql, money,id);
	}
	@Override
	public List<Account> findAll() {
		String sql = "select * from account";
		RowMapper<Account> rowMapper = new BeanPropertyRowMapper<>(Account.class);
		List<Account> accounts = jdbcTemplate.query(sql, rowMapper);
		return accounts;
	}	
}

业务层接口:

public interface IAccountService {
	//转账
	void trans(int fromId,int toId,double money);
	List<Account> findAll();
}

业务层实现类:

@Service
public class AccountServiceImpl implements IAccountService{
	@Autowired
	private AccountDao accountDao;
	@Override
	public void trans(int fromId, int toId, double money) {
		accountDao.decrmentMoney(fromId, money);
		//此处用于测试事务
		int i = 10/0;
		accountDao.incrementMoney(toId, money);		
	}
	@Override
	public List<Account> findAll() {
		return accountDao.findAll();
	}	
}

事务管理相关标签:

<context:property-placeholder>:使得Spring容器将配置文件加载进来
属性:

  • location:配置文件的位置。location=“classpath:文件名”

<tx:advice>:配置事务通知
属性:

  • id:事务通知的唯一标识
  • transaction-manager:值为事务管理器的id值,表示事务通知是哪个事务管理器的通知

<tx:attributes><tx:advice>的子元素,用于配置事务属性

<tx:method>:配置切入点,即要管理的方法。(service实现类中的方法)
属性:

  • name:指定方法的名字,*代表任意方法
  • isolation:指定事务隔离级别
  • propagation:指定事务传播行为
  • read-only:指定是否为只读事务。只读不会自动提交事务
  • rollback-for:指定一个异常,发生指定异常才会回滚,产生其他异常,事务不回滚。
  • no-rollback-for:指定一个异常,产生该异常事务不回滚,产生其他异常事务回滚

rollback-for="java.lang.RuntimeExcetion“:表示发生运行时异常才会回滚,其他异常不回滚

<aop:advisor>:配置切面(通知+切入点)

属性:

  • advice-ref:表示关联的通知,值为事务通知的id值
  • pointcut-ref:表示关联的切入点,值为切入点的id值

配置文件:

<?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
	http://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
	http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 指定需要扫描的包,使注解生效 -->
	<context:component-scan base-package="com.spring.jdbc"/>
	<!-- 导入dataSource.properties文件 -->
	<context:property-placeholder location="classpath:dataSource.properties"/>
	<!-- 创建数据源并配置 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<!-- 数据库驱动 -->
		<property name="driverClassName" value="${jdbc.driverClass}"/>
		<!-- 连接数据库的URL -->
		<property name="url" value="${jdbc.url}"/>
		<!-- 连接数据库的用户名 -->
		<property name="username" value="${jdbc.username}"/>
		<!-- 连接数据库的密码 -->
		<property name="password" value="${jdbc.password}"/>
	</bean>
	<!--创建JDBC模板并配置 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<!-- 关联数据源 -->
		<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 创建事务管理器对象并配置其数据源 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事务通知 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<!-- 配置事务属性 -->
		<tx:attributes>
			<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>
	<!-- 编写AOP,让Spring自动对目标对象生成代理 -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* com.spring.jdbc..*.*(..))" id="pt"/>
		<!-- 关联切入点和通知 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
	</aop:config>
</beans>

测试类:

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
	@Autowired
	private IAccountService accountService;
	@Test
	public void query() {
		List<Account> list = accountService.findAll();
		for(Account account:list) {
			System.out.println(account);
		}
	}
	@Test
	public void testTrans() {
		accountService.trans(1, 2, 300);
	}
}

业务层的转账方法中,转出和转入之间设置了一个异常,
如果applicationContext.xml中不进行事务管理,则会执行转出操作,不执行转入操作。
如果进行事务管理,发生异常时事务会回滚,转入转出都不执行

进行事务管理输出结果:
在这里插入图片进行描述
没进行事务管理输出结果:

在这里插入图片描述

2.基于注解方式的事务管理

实现方式:在业务层实现类上加注解@Transactional,在配置文件中加标签`tx:annotation-driven

@Transactional

  • 该注解用于进行事务管理,可作用于类、类方法、接口、接口方法上。
  • 作用于类上,该类的所有public方法都具有该事务特性。
  • 注解在方法上的优先级>类上>接口上

<tx:annotation-driven>:为事务管理器注解驱动器
属性:transaction-manager:指定是哪个事务管理器

基于XML方式的事务管理需要在配置文件中添加tx:annotation-driven标签,事务才能生效

(1)使用配置文件实现:
业务层实现类:

@Service
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false)
public class AccountServiceImpl implements IAccountService{
	@Autowired
	private AccountDao accountDao;
	
	@Override
	public void trans(int fromId, int toId, double money) {
		accountDao.decrmentMoney(fromId, money);
		//此处用于测试事务
		int i = 10/0;
		accountDao.incrementMoney(toId, money);		
	}
	@Override
	@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.SUPPORTS,readOnly = true)
	public List<Account> findAll() {
		return accountDao.findAll();
	}	
}

配置文件:

<?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
	http://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
	http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 指定需要扫描的包,使注解生效 -->
	<context:component-scan base-package="com.spring.jdbc"/>
	<!-- 导入dataSource.properties文件 -->
	<context:property-placeholder location="classpath:dataSource.properties"/>
	<!-- 创建数据源并配置 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<!-- 数据库驱动 -->
		<property name="driverClassName" value="${jdbc.driverClass}"/>
		<!-- 连接数据库的URL -->
		<property name="url" value="${jdbc.url}"/>
		<!-- 连接数据库的用户名 -->
		<property name="username" value="${jdbc.username}"/>
		<!-- 连接数据库的密码 -->
		<property name="password" value="${jdbc.password}"/>
	</bean>
	<!--创建JDBC模板并配置 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<!-- 关联数据源 -->
		<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 创建事务管理器对象并配置其数据源 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 为事务管理器注册注解驱动器 -->
	<tx:annotation-driven transaction-manager="txManager"/>
</beans>

其余代码同上。

(2)使用配置类实现:

@EnableTransactionManagement:配置类中需要加上该标签,事务管理才能生效

@Configuration
@ComponentScan("com.spring.jdbc")
@EnableTransactionManagement
public class AccountConfig {
	@Bean
	public DataSource dataSource() {
		//创建数据源
		DruidDataSource dataSource= new DruidDataSource();
		dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
		dataSource.setUrl("jdbc:oracle:thin:@localhost:1522:xe");
		dataSource.setUsername("jy");
		dataSource.setPassword("jy");
		dataSource.setInitialSize(5);
		dataSource.setMaxActive(10);
		return dataSource;	
	}
	@Bean
	public JdbcTemplate jdbcTemplate() {
		//创建模板类
		JdbcTemplate jdbcTemplate = new JdbcTemplate();
		//设置模板类的数据源
		jdbcTemplate.setDataSource(dataSource());
		return jdbcTemplate;
	}
	@Bean
	public PlatformTransactionManager manager() {
		//创建事务管理器
		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
		//设置事务管理器的数据源
		transactionManager.setDataSource(dataSource());
		return transactionManager;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值