看了慕课的spring事务管理,然后整理了一下,以便以后自己学习

xiaoxiao2021-02-28  30

事务的特性:     1. 原子性.         事务是一个不可分割的整体,要么都失败,要么都成功     2. 一致性:         事务前后性必须数据的完整性必须保持一致     3. 隔离性:         多个用户并发访问数据库的时候,一个用户的事务不能被其他用户的事务给干扰,         多个并发事务之间数据要相互隔离     4. 持久性:         持久性就是事务一旦提交,那么对于数据库中就是永久性的,不会因为数据库发送事故而改变 事务管理的三个主要接口     platformTransactionManager         事务管理器         spring为不同的持久层框架提供了不同的接口             对于 mybatis,jdbc 使用的是 org.springframework.jdbc.datasource.DataSourceTransaction             对于 hibernate           org.springframework.orm.hibernate3.HibernateTransactionManager             对于 jpa           org.springframework.orm.jpa.JpaTransactionManager             对于 jdo           org.springframework.orm.jdo.JdoTransactionManager             对于 jta(是一个分布式事务) org.springframework.orm.jta.JtaTransactionManager     TransactionDefinition         事务定义信息 (隔离,传播,超时,只读)     TransactionStatus         事务具体运行状态 事务中出现的问题:     1. 脏读:         一个事务读到了另一个事务改写但还未提交的数据,如果这些数据回滚,则读到的数据是无效的     2. 不可重复读:         在同一事务中,多次读取同一数据返回的结果有所不同     3. 幻读:         在一个事务中读取了几行数据,当另一个事务插入了几条数据后,在后来的查询后,发现一些没有的数据. 事务的隔离级别:     DEFAULT        使用后端数据库默认的隔离级别             对于mysql 默认的隔离级别(REPEATABLE_READ)                 oracle  (READ_COMMITED)          READ_UNCOMMITED    允许读取修改还未提交的数据,可能会导致,脏,不可重复,幻读的情况          READ_COMMITED    允许在事务提交以后读取,但不可避免不可重复,幻读的情况          REPEATABLE_READ 对于相同字段多次读取时一致的,除非数据被事务本身改变,可防止脏读,不可重复..但幻读不行          SERIALIZABLE    完全服从ACID的隔离级别,确保不发生脏,幻,不可重复读,这是所有隔离级别中最慢的,它是完全             锁在事务中涉及的数据表来完成的. 事务的传播行为:     当一个功能  需要调用 2个业务层的方法 才能完成, 每个service层的方法都有事务.\     PROPAGATION_REQUIRED *    支持当前事务,如果不存在就新建一个     PROPAGATION_SUPPORTS    支持当前事务,如果不存在就不适用事务,          PROPAGATION_MANDATORY    支持当前事务,如果不存在,抛出异常          PROPAGATION_REQUIRED_NEW * 如果有事务存在,挂起当前事务,新建一个          PROPAGATION_NOT_SUPPORTS 以非事务方式运行,如果事务存在,挂起当前事务     PROPAGATION_NEVER    以非事务方式运行,抛出异常     PROPAGATION_NESTED *    如果当前事务存在咋嵌套事务执行 spring 支持两种事务管理     1. 编程式的事务管理      1. 在实际应用中很少使用      2. 通过TransactionTemplate手动管理事务     使用XML配置声明式事务      1. 开发中推荐使用(代码侵入最小)

     2. Spring的声明式事务式通过AOP实现的

            1. 基于 TransactionProxyFactoryBean (很少使用)        2. 基于 AspectJ的XML方式 (经常使用)            一旦配置好了,不需要在添加任何东西        3. 基于 注解 (经常使用)            配置简单,需要在每个业务层类上面加 @Transcational 注解

做的一个实例 是   转账问题   a 转 b  两个人的账户相应增加,减少,当发生异常,则事务不进行提交,a,b的金额没有发生改变

在 SpringTest 测试类中 需要加入    @RunWith(SpringJUnit4ClassRunner.class) // //使用junit4进行测试      @ContextConfiguration("classpath:applicationContext.xml") // 加载配置文件    这两个注解

 搭建测试环境

    userDao,userDaoImpl

import org.springframework.jdbc.core.support.JdbcDaoSupport; public class UserDaoImpl extends JdbcDaoSupport implements UserDao{ @Override public void outPrice(String name, double price) { // TODO Auto-generated method stub String sql = "update user set price = price - ? where username = ?"; this.getJdbcTemplate().update(sql,price,name); } @Override public void intPrice(String name, double price) { // TODO Auto-generated method stub String sql = "update user set price = price + ? where username = ?"; this.getJdbcTemplate().update(sql,price,name); } } public interface UserDao { /** * 转账 */ public void outPrice(String name,double price); /** * 收账 */ public void intPrice(String name,double price); }

userService,userServiceImpl

public interface UserService { public void out(String name,String name2,double price); } import javax.annotation.Resource; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; public class UserServiceImpl implements UserService{ @Resource(name="userDao") public UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } // 事务模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void out(String name, String name2, double price) { // TODO Auto-generated method stub transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus tr) { // TODO Auto-generated method stub userDao.intPrice(name, price); int a = 1 / 0; userDao.outPrice(name2, price); } } ); } }

1. 编程式的事务管理

    在 service 中使用TransactionTemplate    TransactionTemplate 依赖 DataSourceTransactionManager    DataSourceTransactionManager依赖DataSource构造    1.1 在 applicationContext 中配置事务管理器

<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" > <!-- 数据库配置文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 创建数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" > <property name="driverClassName" value="${driver}"></property> <property name="url" value="${url}"></property> <property name="username" value="${name}"></property> <property name="password" value="${password}"></property> <property name="maxActive" value="10"></property> <property name="maxIdle" value="5"></property> </bean> <!-- 配置数据层 --> <bean id="userDao" class="com.zyh.UserDaoImpl" scope="prototype"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置业务层 --> <bean id="userService" class="com.zyh.UserServiceImpl" scope="prototype"> <property name="userDao" ref="userDao"></property> <!-- 注入事务管理的模板 --> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <!-- 编程式的事务管理 --> <!-- 创建事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 将数据连接注入过来 --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 创建一个 事务管理模板 简化 底层代码 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <!-- 将真正进行事务管理的 注入进来 --> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>

1.2  在 service 实现类中注入 transactionTemplate 模板来实现事务管理

// 当在service 方法中注入了transactionTemplate 那么在 applicationContext 中相应的 service // 也注入transactionTemplate private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate){ this.transactionTemplate = transactionTemplate; } 然后调用 transactionTemplate 中的方法 execute 此方法呢需要一个匿名内部类 new TransactionCallbackWithoutResult(){ @Override protected void doInTransactionWithoutResult(TransactionStatus tr) { // TODO Auto-generated method stub userDao.intPrice(name, price); int a = 1 / 0; userDao.outPrice(name2, price); } }

1.3 然后进行测试

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringTest { @Resource(name="userService") public UserService userService; public void setUserService(UserService userService) { this.userService = userService; } @Test public void springDemo() { userService.out("aaa", "bbb", 200); } }

然后查看数据库,发现中间发生异常,事务是不会提交的

2. spring声明式的事务管理

    声明式的事务管理是基于spring aop思想的

     将环境恢复到 一开始状态,(将所有的关于 transactionTemplate 的都删除)

1. 配置事务管理 <!-- 创建事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 将数据连接注入过来 --> <property name="dataSource" ref="dataSource"></property> </bean>2. 配置代理 <!-- 配置 代理 --> <bean id="userServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置目标对象 --> <property name="target" ref="userService"></property> <!-- 注入事务管理 --> <property name="transactionManager" ref="transactionManager"></property> <!-- 注入事务属性 --> <property name="transactionAttributes"> <props> <!-- prop格式: PROPAGATION : 事务的传播行为 ISOLATION : 事务的隔离级别 readOnly : 只读 -Exception : 发生哪些异常回滚事务 +Exception : 发生那修异常事务不会滚 --> <prop key="out">PROPAGATION_REQUIRED</prop> </props> </property> </bean> 然后service层不需要再进行修改了,只需要修改SpringTest

    将userService的 注入换为 userServiceProxy

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; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class SpringTest { /** * 注入代理类 */ // @Resource(name="userService") @Resource(name="userServiceProxy") public UserService userService; @Test public void springDemo() { userService.out("aaa", "bbb", 200); } }

然后进行测试.成功,   当有异常的时候是不会进行 事务提交,没有异常正常提交事务.

然后在 配置文件 bean userServiceProxy 的 事务属性中

<!-- 注入事务属性 --> <property name="transactionAttributes"> <props> <!-- prop格式: PROPAGATION : 事务的传播行为 ISOLATION : 事务的隔离级别 readOnly : 只读 -Exception : 发生哪些异常回滚事务 +Exception : 发生那修异常事务不会滚 --> <prop key="out">PROPAGATION_REQUIRED,readOnly</prop> </props> </property>

多配置一个readonly 然后进行测试会 报异常

因为进行的是修改操作.所有当设置为只读的话 就会报异常

上面那个是第一种方式 基于 TransactionProxyFactoryBean的原始方式        缺点 只能对一个业务层类 管理,当有多个模块的话就需要配置多个Proxy来实现事务管理    声明式事务管理,第二种方式As

    在 applicationConext 中

    

<!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- propagation : 事务传播行为 isolation : 事务隔离级别 readOnly : 只读 rollback-for : 发生哪些异常回滚 no-rollback-for: 发生哪些异常不回滚 timeout : 过期信息 --> <tx:method name="out" propagation="REQUIRED" isolation="DEFAULT" /> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* zyh.UserService+.*(..))" id="pointcut1"/> <aop:advisor advice-ref="pointcut1" pointcut="pointcut1"/> </aop:config> 这种方式的只需要在配置文件配置后就可以 实现对事务管理, 代理对象在对应类生成时生成 第三种 基于注解的 声明式事务管理 <!-- 开启事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/> 然后只需要在 指定的类上面添加Transactional /** * propagation : 事务传播行为 isolation : 事务隔离级别 readOnly : 只读 rollback-for : 发生哪些异常回滚 no-rollback-for: 发生哪些异常不回滚 timeout : 过期信息 */ @Transactional public class UserServiceImpl implements UserService
转载请注明原文地址: https://www.6miu.com/read-2629744.html

最新回复(0)