Spring系列之事务的控制 注解实现+xml实现

在前面我写过一篇关于事务的文章,大家可以先去看看那一篇再看这一篇,学习起来会更加得心应手

链接https://blog.csdn.net/pjh88/article/details/107574137

编程式事务控制对象

事务管理器:PlatformTransactionManager

PlatformTransactionManager是事务的管理器,他提供了我们常用的事务操作方法

为什么PlatformTransactionManager是接口类型?

因为不同的dao层技术有不同的实现类

Dao层是jdbc时:org.springframework.jdbc.datasource.DataSourceTransactionManager

Dao层是mybatis时:org.springframework.orm.hibernate5.HibernateTransactionManager

事务的定义信息对象:TransactionDefinition

TransactionDefinition

里面的方法



**

事务的隔离级别

**

ISOLATION_READ_UNCOMMITTED(读未提交)

实质:一个事务读取另一个事务未提交的数据

例子:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。

ISOLATION_READ_COMMITTED(读已提交)

实质:一个用户读取另一个用户已提交的数据

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

ISOLATION_REPEATABLE_READ(重复读)

实质:一个事务在读取数据时,其他事务不允许进行修改操作

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

ISOLATION_SERIALIZABLE(幻读)

事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。

**

事务的传播行为

**

REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)

MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常

REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。

NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

NEVER:以非事务方式运行,如果当前存在事务,抛出异常

NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作

超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置

是否只读:建议查询时设置为只读

TransactionStatus:事务的具体运行状态

TransactionStatus接口提供的是事务具体的运行状态,方法如下



编程式事务控制的三大对象

PlatformTransactionManager

TransactionDefinition

TransactionStatus

基于XML的声明式事务控制

Spring的声明式事务控制顾名思义就是使用声明的方式来处理事务,这里的声明指的是在配置文件中声明,Spring配置文件中的声明式处理来代替代码式的事务处理

声明式事务处理的作用

事务处理是不侵入开发的组件,具体来说,业务逻辑对象不会意识带正在处于事务处理之中,事实上也应该如此,因为事务管理是出于系统层面的职务,而不是业务逻辑处理的一部分,如果要改变事务管理策划的话,也只需要在定义文件中重新配置即可

在不需要事务管理的时候,只要在设定的文件上修改一下,即可移除事务管理服务,不需要改变代码重新编译,这样维护起来更加方便

Spring事务控制的底层就是AOP

声明式事务控制的实现

切点:需要被事务管理的方法,即业务方法

通知/增强:事务增强

切面:二者结合

下面通过一个银行业务转账的案例来方便大家理解

1.创建数据库和实体

表名:account

字段名:moey--钱,Name--客户名

CREATE TABLE account(
NAME VARCHAR(10),
money DOUBLE
);

插入三个字段值

INSERT INTO account VALUE('tom',1),('bob',2),('jack',3);

2.需要导入的坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId>
<artifactId>spring-mysql</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

3.创建实体类

package com.pjh.account;

public class account {
private double money;
private String name; @Override
public String toString() {
return "account{" +
"money=" + money +
", name='" + name + '\'' +
'}';
} public double getMoney() {
return money;
} public void setMoney(double money) {
this.money = money;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

4.dao层(执行语句,与数据库交互)

接口

package com.pjh.dao;

public interface ServiceDao {
public void inman(String inName,double money);
public void outman(String outName,double money);
}

实现类

package com.pjh.dao.imp;
import com.pjh.dao.ServiceDao;
import org.springframework.jdbc.core.JdbcTemplate; public class ServiceDaoImp implements ServiceDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
} public void inman(String inName, double money) {
jdbcTemplate.update("update account set money=money-? where name =?",money,inName);
}
public void outman(String outName, double money) {
jdbcTemplate.update("update account set money=money+? where name =?",money,outName);
}
}

5.service层

接口

package com.pjh.service;

public interface service {
public void trasfer(String inName,String outName,double money);
}

实现类

package com.pjh.service.Imp;
import com.pjh.dao.imp.ServiceDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired; public class serviceImp implements service { private ServiceDaoImp serviceDaoImp; public void setServiceDaoImp(ServiceDaoImp serviceDaoImp) {
this.serviceDaoImp = serviceDaoImp;
} public void trasfer(String inName, String outName, double money) {
serviceDaoImp.inman(inName,money); serviceDaoImp.outman(outName,money);
}
}

6.applicationContext配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="password" value="${jdbc.password}"/>
<property name="user" value="${jdbc.name}"/>
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="serviceDaoImp" class="com.pjh.dao.imp.ServiceDaoImp">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--目标对象 内部方法就是切点-->
<bean id="serviceImp" class="com.pjh.service.Imp.serviceImp">
<property name="serviceDaoImp" ref="serviceDaoImp"></property>
</bean>
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--通知 事务的增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置事务的织入-->
<aop:config proxy-target-class="true">
<aop:pointcut id="txPointcut" expression="execution(* com.pjh.service.Imp.serviceImp.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<context:property-placeholder location="classpath:jdbc.properties"/>
<context:component-scan base-package="com.pjh"/>
</beans>

7.主函数

package com.pjh.control;
import com.pjh.service.Imp.serviceImp;
import com.pjh.service.service;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class control2 {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
service bean1 =(service) classPathXmlApplicationContext.getBean(service.class);
bean1.trasfer("tom","jack",100);
}
}

结果

成功转账

**

下面我们重点来讲讲切点方法的事务配置

**

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<tx:method >:代表事务参数方法的配置

这个部分一定要重点掌握这是核心

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
name:切点方法名称
isolation:事务的隔离级别
propogation:事务的传播行为
timeout:超时时间
read-only:是否只读

使用注解的方式进行事务的配置

1.dao层

package com.pjh.dao.imp;
import com.pjh.dao.ServiceDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository; @Repository("ServiceDaoImp")
public class ServiceDaoImp implements ServiceDao {
@Autowired
private JdbcTemplate jdbcTemplate; public void inman(String inName, double money) {
jdbcTemplate.update("update account set money=money-? where name =?",money,inName);
}
public void outman(String outName, double money) {
jdbcTemplate.update("update account set money=money+? where name =?",money,outName);
}
}

2.service层

package com.pjh.service.Imp;
import com.pjh.dao.imp.ServiceDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("serviceImp")
@Transactional
public class serviceImp implements service {
@Autowired
private ServiceDaoImp serviceDaoImp; public void trasfer(String inName, String outName, double money) {
serviceDaoImp.inman(inName,money);
//int a=1/0;
serviceDaoImp.outman(outName,money);
}
}

3.编写applicationContext的内容

<!--组件扫描-->
<context:component-scan base-package="com.pjh"/>
<!--事务的注解驱动-->
<tx:annotation-driven/>

小总结

1.使用 @Transactional 在需要进行事务控制的类或是方法上修饰,注解可用的属性同 xml 配置方式,例如隔离级别、传播行为等。

注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。

使用在方法上,不同的方法可以采用不同的事务参数配置。

2.Xml配置文件中要开启事务的注解驱动<tx:annotation-driven />

以上就是Spring系列之事务的控制 注解实现+xml实现的知识点,如果各位觉得有帮助还请点赞关注支持作者,我也会在学习过程中不断更新文章,目前主要是java开发和数据结构的一些知识,愿我们一同进步,圆梦大厂,欢迎私信评论交流

Spring系列之事务的控制 注解实现+xml实现+事务的隔离等级的更多相关文章

  1. Spring系列之aAOP AOP是什么?+xml方式实现aop+注解方式实现aop

    Spring系列之aop aop是什么?+xml方式实现aop+注解方式实现aop 什么是AOP? AOP为Aspect Oriented Programming 的缩写,意识为面向切面的编程,是通过 ...

  2. Spring、Spring事务详解;使用XML配置事务

    @Transactional可以设置以下参数: @Transactional(readOnly=false) // 指定事务是否只读的 true/false @Transactional(rollba ...

  3. spring学习(四)使用注解代替xml配置

    用的是IDEA的maven工程,pom.xml文件导包依赖省略 一.书写要导入容器的实体类 import org.springframework.beans.factory.annotation.Va ...

  4. 阶段3 2.Spring_10.Spring中事务控制_8 spring基于纯注解的声明式事务控制

    新建项目 把之前项目src下的内容全部复制过来 pom.xml内复制过来 开始配置 新建一个config的包,然后再新建配置文件类SpringConfiguration @Configuration这 ...

  5. Spring声明式事务(xml配置事务方式)

    Spring声明式事务(xml配置事务方式) >>>>>>>>>>>>>>>>>>>& ...

  6. Spring对于事务的控制@Transactional注解详解

    引用自:https://blog.csdn.net/fanxb92/article/details/81296005 先简单介绍一下Spring事务的传播行为: 所谓事务的传播行为是指,如果在开始当前 ...

  7. 阶段3 2.Spring_10.Spring中事务控制_7 spring基于注解的声明式事务控制

    创建新项目 复制上一个pom.xml的内容.依赖和打包的方式 再复制src的代码过来 bean.xml.多导入context的声明 Service的实现类增加注解 dao的set方法删掉 通过Auto ...

  8. spring基于注解的声明式事务控制

    package com.hope.service.impl;import com.hope.dao.IAccountDao;import com.hope.domain.Account;import ...

  9. 阶段3 2.Spring_10.Spring中事务控制_3 作业-基于注解的AOP实现事务控制及问题分析_下

    此时没有异常 测试我们的方法 执行报错 注解在实际的测试过程中,实际的执行顺序是有问题的.会先调用最终通知.然后再调用后置通知 最终通知已经关闭了连接.再调用后置通知肯定报错. getThreadCo ...

随机推荐

  1. 学习seo赚钱一定要有超前的思路和眼光

    http://www.wocaoseo.com/thread-100-1-1.html        日子过的真是快,一天又一天,一年又一年,虽然过年的脚步将近,火车票的问题还是没有解决,昨天忙活了半 ...

  2. 读取手机中的联系人信息(android.provider.ContactsContract)

    本篇开始讲如何从Android中得到本机联系人的信息.由于Android较快的版本升级,部分API已经发生了变化.本篇探究的通过ContentProvider机制获取联系人的API从Android2. ...

  3. 关于windou环境下使用http或者ftp搭建网络hu共享

    第一步 右键此电脑进入控制面 第二步:进入程序点击启用或关闭windous功能 第三步进入服务开启界面 点击让windows更新为你下载文件,并保存更改完,然后关闭 四:邮件我的电脑进入管理 四右键添 ...

  4. 【Gin-API系列】Gin中间件之鉴权访问(五)

    在完成中间件的介绍和日志中间件的代码后,我们的程序已经基本能正常跑通了,但如果要上生产,还少了一些必要的功能,例如鉴权.异常捕捉等.本章我们介绍如何编写鉴权中间件. 鉴权访问,说白了就是给用户的请求增 ...

  5. 开源流数据公司 StreamNative 推出 Pulsar 云服务,推进企业“流优先”进程

    Apache 顶级项目 Pulsar 背后的开源流数据公司 StreamNative 宣布,推出基于 Apache Pulsar 的云端服务产品--StreamNative Cloud.该产品的发布, ...

  6. Fibonacci and Counting(水题)

    链接:https://ac.nowcoder.com/acm/contest/303/B 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5242 ...

  7. Spring security OAuth2.0认证授权学习第二天(基础概念-RBAC)

    RBAC 基于角色的访问控制 基于角色的访问控制用代码实现一下其实就是一个if的问题if(如果有角色1){ } 如果某个角色可以访问某个功能,当某一天其他的另一个角色也可以访问了,那么代码就需要变化, ...

  8. (高难度SQL)从产品表中找出相同前缀 (都云作者痴 谁解其中味)

    --期盼值 找出AA,3;PDST,3;QPL-,3;TP-,2; --基本表 create table tb_product( id number(9,0) primary key, name nv ...

  9. Redis6.0.6集群服务搭建

    实现目标 一台主机上搭建3主3从高可用redis集群 环境 Linux :CentOS7 Redis : 6.0.6 准备工作 1.查看是否有安装wget命令,如果没有安装使用yum命令安装wgt命令 ...

  10. Java网络通信 —— 序列化问题

    Java序列化的目的主要有两个: 1.网络传输 2.对象持久化 当选行远程跨迸程服务调用时,需要把被传输的Java对象编码为字节数组或者ByteBuffer对象.而当远程服务读取到ByteBuffer ...