《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

回到顶部