《Java Spring框架》Spring事务管理
本文内容纲要:《Java Spring框架》Spring事务管理
1、 事务相关知识:
什么是事务:把多条数据库操作捆绑到一起执行,要么都成功,要么都失败;
事务的原则ACID:
原子性:事务包含的所有操作,要么全部成功,要么全部失败回滚,成功全部应用到数据库,失败不能对数据库有任何影响;
一致性:事务在执行前和执行后必须一致;例如A和B一共有100块钱,无论A、B之间如何转账,他们的钱始终相加都是100;
隔离性:多用户并发访问同一张表时,数据库为每一个用户开启新的事务,该事务不能被其他事务所影响,相互有隔离;
持久性:一个事务一旦提交,则对数据库中数据的改变是永久的,即便系统故障也不会丢失;
并发可能引起的问题:
脏读:一个事务读取到另一个事务未提交的数据;
不可重复读:一个事务读取到另一个事务已提交(Update操作)的数据,导致前后读取不一致;
幻读(虚读):一个事务中读取到别的事务插入(Insert操作)的数据,导致前后读取不一致;
事务的隔离级别:根据实际情况选择;
Serializable串行化:可避免脏读、不可重复读和幻读;
Repeatable read可重复读:可避免脏读、不可重复读;(MySql默认值)
Read committed读已提交:可避免脏读;
Read uncommitted读未提交:任何情况都无法保证;
2、 Spring-aop事务-搭建环境;
事务基本操作:打开事务、提交事务、回滚事务;
Spring中利用接口来管理不同框架的事务操作;
通过实现PlatformTransactionManager接口支持不同的框架完成各自的事务处理;
为不同平台提供对应的事务管理器的实现:
JDBC&Mybatis:DataSourceTransactionManager;
Spring-aop事务通过配置事务的隔离级别、事务传播行为、是否只读来操作;
隔离级别:串行化、可重复读、读已提交、读未提交;
是否只读:true:不可改变数据库中的数据,查询操作推荐; false:可以改变数据库数据;
事务传播行为:事务方法嵌套调用的规则: xService.x(); -> yService.y();
REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置;
REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务;
SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行;
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起(暂停);
MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常;
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常;
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。
3、 Spring-aop事务 – 从麻烦的事务代码中走出之xml配置版aop事务;
使用经典的转账案例进行测试,准备数据:bean、service、dao;
使用事务需要额外导入tx包和tx约束;
配置事务核心管理器: DataSourceTransactionManager;
配置事务通知 tx:Advice;
配置aop;
根据以上知识点,我们来实现spring的事务管理。
数据库创建一张表:
代码:
/** * 账户
* @author hubt11585
*/
public class Account {
private Integer id;
private String name;
private Double 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 Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
public interface AccountDao {
//扣款
void subMoney(Integer id, Double money);
//加款
void addMoney(Integer id, Double money);
}
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void subMoney(Integer id, Double money) {
String sql = "update account set money = money - ? where id = ?";
getJdbcTemplate().update(sql, money, id);
}
@Override
public void addMoney(Integer id, Double money) {
String sql = "update account set money = money + ? where id = ?";
getJdbcTemplate().update(sql, money, id);
}
}
/**
* 账户service
* @author Joey
*
*/
public interface AccountService {
//转账接口
void transferAccounts();
}
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.tao.dao.AccountDao;
@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRED, readOnly=true)
public class AccountServiceImpl implements AccountService {
//账户dao
private AccountDao ad;
public void setAd(AccountDao ad) {
this.ad = ad;
}
@Override
@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRED, readOnly=false)
public void transferAccounts() {
//转账逻辑
//先从A账户扣款
ad.subMoney(1, 50d);
int a = 1/0; // 除以0会出现异常
//再给B账户加款
ad.addMoney(2, 50d);
}
}
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.tao.service.AccountService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TxTest {
@Resource(name="accountService")
private AccountService as;
@Test
public void Test1() {
as.transferAccounts();
}
}
配置文件: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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 依赖关系 dao -> -> dataSource -->
<!-- 读取配置文件 -->
<context:property-placeholder location="db.properties"/>
<!-- 配置 dataSource -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- dao -->
<bean name="accountDao" class="com.tao.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- service -->
<bean name="accountService" class="com.tao.service.AccountServiceImpl">
<property name="ad" ref="accountDao"/>
</bean>
<!-- 配置事务核心管理器 不同平台不一样 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务通知 -->
<tx:advice id="txAdivce" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transferAccounts" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="select*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop -->
<aop:config>
<aop:pointcut expression="execution(* com.tao.service.*ServiceImpl.*(..))" id="txPc"/>
<aop:advisor advice-ref="txAdivce" pointcut-ref="txPc"/>
</aop:config>
</beans>
运行结果:
会出现异常
表里面数据被回滚,并没有出现执行了异常前面部分,效果达到。
以下是注解版代码:
只需要调整一下部分代码。
配置文件中:开启事务:
完整配置文件如下:
<?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-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 依赖关系 dao -> -> dataSource -->
<!-- 读取配置文件 -->
<context:property-placeholder location="db.properties"/>
<!-- 配置 dataSource -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- dao -->
<bean name="accountDao" class="com.tao.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- service -->
<bean name="accountService" class="com.tao.service.AccountServiceImpl">
<property name="ad" ref="accountDao"/>
</bean>
<!-- 配置事务核心管理器 不同平台不一样 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven/>
</beans>
代码:AccountServiceImpl类上(整个类下所有方法有效)或者方法上加上注解即可实现统一事务。
import org.springframework.transaction.annotation.Isolation;import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.tao.dao.AccountDao;
@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRED, readOnly=true)
public class AccountServiceImpl implements AccountService {
//账户dao
private AccountDao ad;
public void setAd(AccountDao ad) {
this.ad = ad;
}
@Override
@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRED, readOnly=false)
public void transferAccounts() {
//转账逻辑
//先从A账户扣款
ad.subMoney(1, 50d);
int a = 1/0; // 除以0会出现异常
//再给B账户加款
ad.addMoney(2, 50d);
}
}
运行结果:
会出现异常
表里面数据被回滚,并没有出现执行了异常前面部分,效果达到。
总结:通过spring来控制事务,方便整洁。
本文内容总结:《Java Spring框架》Spring事务管理
原文链接:https://www.cnblogs.com/jssj/p/12148828.html
以上是 《Java Spring框架》Spring事务管理 的全部内容, 来源链接: utcz.com/z/362770.html