ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

013_Spring事务

2021-02-06 19:00:57  阅读:114  来源: 互联网

标签:事务 String Spring void 013 money public name


一. 事务

1. 什么事务?

1.1. 事务: 逻辑上的一组操作, 组成这组操作的各个单元, 要么全都成功, 要么全都失败。

2. 事务的特性

2.1. 原子性: 事务不可分割。

2.2. 一致性: 事务执行前后数据完整性保持一致。

2.3. 隔离性: 一个事务的执行不应该受到其他事务的干扰。

2.4. 持久性: 一旦事务结束, 数据就持久化到数据库。

3. 如果不考虑隔离性引发安全性问题

3.1. 读问题

3.1.1. 脏读: 一个事务读到另一个事务未提交的数据。

3.1.2. 不可重复读: 一个事务读到另一个事务已经提交的update的数据, 导致一个事务中多次查询结果不一致。

3.1.3. 虚读、幻读: 一个事务读到另一个事务已经提交的insert的数据, 导致一个事务中多次查询结果不一致。

3.2. 写问题

3.2.1. 丢失更新

4. 设置事务的隔离级别解决读问题

4.1. Read uncommitted: 未提交读, 任何读问题解决不了。

4.2. Read committed: 已提交读, 解决脏读, 但是不可重复读和虚读有可能发生。

4.3. Repeatable read: 重复读, 解决脏读和不可重复读, 但是虚读有可能发生。

4.4. Serializable: 解决所有读问题。

二. Spring的事务管理的API

1. PlatformTransactionManager平台事务管理器接口

1.1. DataSourceTransactionManager: 底层使用JDBC管理事务。

1.2. HibernateTransactionManager: 底层使用Hibernate管理事务。

2. TransactionDefinition事务定义信息

2.1. 事务定义: 用于定义事务的相关的信息, 隔离级别、超时信息、传播行为、是否只读。

3. TransactionStatus事务的状态

3.1. 事务状态: 用于记录在事务管理过程中, 事务的状态的对象。

4. 事务管理的API的关系

4.1. Spring进行事务管理的时候, 首先平台事务管理器根据事务定义信息进行事务的管理, 在事务管理过程中, 产生各种状态, 将这些状态的信息记录到事务状态的对象中。

5. Spring中提供了七种事务的传播行为:

5.1. 保证多个操作在同一个事务中

5.1.1. PROPAGATION_REQUIRED: 默认值, 如果A中有事务, 使用A中的事务, 如果A没有, 创建一个新的事务, 将操作包含进来。

5.1.2. PROPAGATION_SUPPORTS: 支持事务, 如果A中有事务, 使用A中的事务。如果A没有事务, 不使用事务。

5.1.3. PROPAGATION_MANDATORY: 如果A中有事务, 使用A中的事务。如果A没有事务, 抛出异常。

5.2. 保证多个操作不在同一个事务中

5.2.1. PROPAGATION_REQUIRES_NEW: 如果A中有事务, 将A的事务挂起(暂停), 创建新事务, 只包含自身操作。如果A中没有事务, 创建一个新事务, 包含自身操作。

5.2.2. PROPAGATION_NOT_SUPPORTED: 如果A中有事务, 将A的事务挂起。不使用事务管理。

5.2.3. PROPAGATION_NEVER: 如果A中有事务, 报异常。

5.3. 嵌套式事务

5.3.1. PROPAGATION_NESTED: 嵌套事务, 如果A中有事务, 按照A的事务执行, 执行完成后,设置一个保存点, 执行B中的操作, 如果没有异常, 执行通过, 如果有异常, 可以选择回滚到最初始位置, 也可以回滚到保存点。

三. 编程式事务

1. 配置平台事务管理器

2. Spring提供了事务管理的模板类

3. 在业务层注入事务管理的模板

4. 编写事务管理的代码

5. 例子

5.1. 新建一个名为SpringJdbcProgramTx的Java工程, 拷入相关jar包

5.2. 新建一个Account.java

package com.lywgames.tx;

import java.io.Serializable;

public class Account implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String name;
	private Float money;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Float getMoney() {
		return money;
	}

	public void setMoney(Float money) {
		this.money = money;
	}

	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
	}

}

5.3. 新建一个AccountDao.java数据库操作接口

package com.lywgames.tx;

/**
 * 转账的Dao的接口
 */
public interface AccountDao {
	public void outMoney(String from, Float money);

	public void inMoney(String to, Float money);
}

5.4. 新建一个AccountDaoImpl.java数据库操作实现类

package com.lywgames.tx;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * 转账的Dao的实现类
 */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	@Override
	public void outMoney(String from, Float money) {
		getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
	}

	@Override
	public void inMoney(String to, Float money) {
		getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
	}

}

5.5. 新建一个AccountService.java业务接口

package com.lywgames.tx;

/**
 * 转账的业务层的接口
 */
public interface AccountService {
	public void transfer(String from, String to, Float money);
}

5.6. 新建一个AccountServiceImpl.java业务实现类

package com.lywgames.tx;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 转账的业务层的实现类
 */
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;
	
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	private TransactionTemplate transactionTemplate;
	
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
	
	/**
	 * from: 转出账号
	 * to: 转入账号
	 * money: 转账金额
	 */
	@Override
	public void transfer(String from, String to, Float money) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
				accountDao.outMoney(from, money);
				int d = 1/0;
				accountDao.inMoney(to, money);
			}
		});
	}

}

5.7. 新建一个Test.java测试类

package com.lywgames.tx;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService accountService = context.getBean(AccountService.class);
		accountService.transfer("王五", "李四", 100.00F);
		context.close();
	}
}

5.8. 在src目录下创建log4j.properties日志配置

5.9. 在src目录下创建jdbc.properties数据库连接配置

5.10. 在src目录下创建applicationContext.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"
	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">

	<!-- 通过context标签引入属性文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

	<!-- 配置Spring内置连接池 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"></property>
		<property name="url" value="${jdbc.url}"></property>
		<property name="username" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>

	<!-- 配置平台事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 配置事务管理的模板 -->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager" />
	</bean>

	<!-- Dao继承了JdbcDaoSupport, 可以不配置jdbcTemplate模板bean, 在注入dataSource属性时, 会自动创建jdbcTemplate。 -->
	<bean id="accountDao" class="com.lywgames.tx.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="accountService" class="com.lywgames.tx.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
		<!-- 注入事务管理的模板 -->
		<property name="transactionTemplate" ref="transactionTemplate" />
	</bean> 
</beans>

5.11. 查看account表

5.12. 运行项目, 抛出异常, 查看数据库结果, 转载失败, 每个人的钱数不变

5.13. 注释掉异常, 运行项目, 查看数据库结果, 转账成功

四. 声明式事务管理(XML方式的声明式事务管理)

1. 配置平台事务管理器

2. 配置增强

3. AOP的配置

4. 例子

4.1. 新建一个名为SpringJdbcXmlTx的Java工程, 拷入相关jar包

4.2. 新建一个Account.java

package com.lywgames.tx;

import java.io.Serializable;

public class Account implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String name;
	private Float money;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Float getMoney() {
		return money;
	}

	public void setMoney(Float money) {
		this.money = money;
	}

	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
	}

}

4.3. 新建一个AccountDao.java数据库操作接口

package com.lywgames.tx;

/**
 * 转账的Dao的接口
 */
public interface AccountDao {
	public void outMoney(String from, Float money);

	public void inMoney(String to, Float money);
}

4.4. 新建一个AccountDaoImpl.java数据库操作实现类

package com.lywgames.tx;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * 转账的Dao的实现类
 */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	@Override
	public void outMoney(String from, Float money) {
		getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
	}

	@Override
	public void inMoney(String to, Float money) {
		getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
	}

}

4.5. 新建一个AccountService.java业务接口

package com.lywgames.tx;

/**
 * 转账的业务层的接口
 */
public interface AccountService {
	public void transfer(String from, String to, Float money);
}

4.6. 新建一个AccountServiceImpl.java业务实现类

package com.lywgames.tx;

/**
 * 转账的业务层的实现类
 */
public class AccountServiceImpl implements AccountService {

	private AccountDao accountDao;
	
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	/**
	 * from: 转出账号
	 * to: 转入账号
	 * money: 转账金额
	 */
	@Override
	public void transfer(String from, String to, Float money) {
		accountDao.outMoney(from, money);
		int d = 1/0;
		accountDao.inMoney(to, money);
	}

}

4.7. 新建一个Test.java测试类

package com.lywgames.tx;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService accountService = context.getBean(AccountService.class);
		accountService.transfer("王五", "李四", 100.00F);
		context.close();
	}
}

4.8. 在src目录下创建log4j.properties日志配置

4.9. 在src目录下创建jdbc.properties数据库连接配置

4.10. 在src目录下创建applicationContext.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: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 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">

	<!-- 通过context标签引入属性文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

	<!-- 配置Spring内置连接池 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"></property>
		<property name="url" value="${jdbc.url}"></property>
		<property name="username" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- 配置事务管理的模板 -->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager" />
	</bean>

	<!-- Dao继承了JdbcDaoSupport, 可以不配置jdbcTemplate模板bean, 在注入dataSource属性时, 会自动创建jdbcTemplate。 -->
	<bean id="accountDao" class="com.lywgames.tx.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="accountService" class="com.lywgames.tx.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
	</bean> 
	
	<!-- 配置事务的增强 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- name="*" 表示所有方法 -->
			<tx:method name="*" propagation="REQUIRED" read-only="false"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- aop的配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.lywgames.tx.AccountServiceImpl.*(..))" id="pointcut"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
	</aop:config>
</beans>

4.11. 查看account表

4.12. 运行项目, 抛出异常, 查看数据库结果, 转载失败, 每个人的钱数不变

4.13. 注释掉异常, 运行项目, 查看数据库结果, 转账成功

五. 声明式事务管理(注解方式的声明式事务管理)

1. 配置平台事务管理器

2. 开启注解事务

3. 在业务层添加注解

4. 例子

4.1. 新建一个名为SpringJdbcAnnotationTx的Java工程, 拷入相关jar包

4.2. 新建一个Account.java

package com.lywgames.tx;

import java.io.Serializable;

public class Account implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String name;
	private Float money;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Float getMoney() {
		return money;
	}

	public void setMoney(Float money) {
		this.money = money;
	}

	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
	}

}

4.3. 新建一个AccountDao.java数据库操作接口

package com.lywgames.tx;

/**
 * 转账的Dao的接口
 */
public interface AccountDao {
	public void outMoney(String from, Float money);

	public void inMoney(String to, Float money);
}

4.4. 新建一个AccountDaoImpl.java数据库操作实现类

package com.lywgames.tx;

import javax.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

/**
 * 转账的Dao的实现类
 */
@Component(value="accountDao")
public class AccountDaoImpl implements AccountDao {

	@Resource(name="jdbcTemplate")
	private JdbcTemplate jdbcTemplate;
	
	@Override
	public void outMoney(String from, Float money) {
		jdbcTemplate.update("update account set money = money - ? where name = ?", money, from);
	}

	@Override
	public void inMoney(String to, Float money) {
		jdbcTemplate.update("update account set money = money + ? where name = ?", money, to);
	}

}

4.5. 新建一个AccountService.java业务接口

package com.lywgames.tx;

/**
 * 转账的业务层的接口
 */
public interface AccountService {
	public void transfer(String from, String to, Float money);
}

4.6. 新建一个AccountServiceImpl.java业务实现类

package com.lywgames.tx;

import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 转账的业务层的实现类
 */
@Transactional
@Component(value="accountService")
public class AccountServiceImpl implements AccountService {

	@Resource(name="accountDao")
	private AccountDao accountDao;
	
	/**
	 * from: 转出账号
	 * to: 转入账号
	 * money: 转账金额
	 */
	@Override
	public void transfer(String from, String to, Float money) {
		accountDao.outMoney(from, money);
		int d = 1/0;
		accountDao.inMoney(to, money);
	}

}

4.7. 新建一个Test.java测试类

package com.lywgames.tx;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService accountService = context.getBean(AccountService.class);
		accountService.transfer("王五", "李四", 100.00F);
		context.close();
	}
}

4.8. 在src目录下创建log4j.properties日志配置

4.9. 在src目录下创建jdbc.properties数据库连接配置

4.10. 在src目录下创建applicationContext.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: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 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">

	<!-- 使用IOC的注解开发, 配置组件扫描, 哪些包下的类使用了IOC的注解 -->
	<context:component-scan base-package="com.lywgames"></context:component-scan>

	<!-- 通过context标签引入属性文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

	<!-- 配置Spring内置连接池 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"></property>
		<property name="url" value="${jdbc.url}"></property>
		<property name="username" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- 开启注解事务 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
	
	<!-- 配置Spring的Jdbc模板 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

4.11. 查看account表

4.12. 运行项目, 抛出异常, 查看数据库结果, 转载失败, 每个人的钱数不变

4.13. 注释掉异常, 运行项目, 查看数据库结果, 转账成功

标签:事务,String,Spring,void,013,money,public,name
来源: https://blog.csdn.net/aihiao/article/details/113728863

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有