Spring 使用注解对事务控制详解与实例
1.什么是事务
一荣俱荣,一损俱损,很多复杂的操作我们可以把它看成是一个整体,要么同时成功,要么同时失败。
事务的四个特征ACID:
原子性(Atomic):表示组成一个事务的多个数据库的操作的不可分割的单元,只有所有的操作成功才算成功,整个事务提交,其中任何一个操作失败了都是导致整个所有操作失败,事务会回滚。
一致性(Consistentcy):事务操作成功后,数据库所处的状态和业务规则一致。如果A账户给B账户汇100,A账户减去100,B加上100,两个账户的总额是不变的。
隔离性(islation):在多个数据库的操作相同的数据并发时,不同的事务有自己的数据空间,事务与事务之间不受干扰(不是绝对的)。干扰程度受数据库或者操作事务的隔离级别来决定,隔离级别越高,干扰就越低,数据的一致性越好,并发性就越差。
持久性(Druability):一旦事务提交成功,数据就被持久化到数据库,不可以回滚。
2.spring使用注解对事务的控制
Spring 事务管理有两种方式:编程式事务管理、声明式事务管理
编程式事务管理通过TransactionTemplate手动管理事务,在实际应用中很少使用,我们来重点学习声明式事务管理
声明式事务管理有三种实现方式:基于TransactionProxyFactoryBean的方式、基于AspectJ的XML方式、基于注解的方式
1. 新建一个java工程——导入spring 和事务管理所需要的jar ——然后选择全部jar 右键Build path ——最后如图 (我的java版本jre是1.8) Spring事务需要的jar

2.在src目录下新建5个包 如图
dao :数据连接层,主要用于存放对数据进行操作的类
model:模型层,主要用于存放实体类
service:服务层,主要用于对数据连接层进行操作的一些服务类。
util:工具类,主要用于存储工具方法
test:用于测试类

3.在dao数据连接层,建立里与数据库操作的类与对应的接口 (Order 订单 ,detail订单明细)
3.1 定义detailDao接口 代码如下:
package com.spring.dao; import com.spring.model.Detail;
import com.spring.model.Order; public interface detailDao {
//保存订单明细
public void saveDetail(Detail detail); }
3.2 定义OrderDao接口 代码如下:
package com.spring.dao;
import com.spring.model.Order;
public interface OrderDao {
//保存订单
public void saveOrder(Order order);
}
3.3 实现以上接口
detailDaoImp 代码如下:
package com.spring.dao; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; import com.spring.model.Detail;
import com.spring.model.Order; public class detailDaoImp implements detailDao { private DataSource dataSource;
private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
//保存订单明细
public void saveDetail(Detail detail) {
String SQL = "insert into t_detail values(null,?,?,?))";
jdbcTemplate.update(SQL, new Object[] { detail.getItemName(),detail.getQuantity(),detail.getOrderId() });
System.out.println("Insert detail success!");
} }
OrderDaoImp代码如下:
package com.spring.dao;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.spring.model.Order;
public class OrderDaoImp implements OrderDao {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
//插入订单
public void saveOrder(Order order) {
String SQL = "insert into t_order values (null,?)";
System.out.println(SQL);
System.out.println(order.getTotal_price());
jdbcTemplate.update(SQL, new Object[]{order.getTotal_price()});
System.out.println("Insert order success!");
}
}
4.在model层中新建两个实体类 (Order订单类,detail订单明细类)
Order订单类代码如下:
package com.spring.model; /*
* 订单表
*/
public class Order {
//订单编号
private Integer order_id;
//订单总金额
private Integer total_price;
public Integer getOrder_id() {
return order_id;
}
public void setOrder_id(Integer order_id) {
this.order_id = order_id;
}
public Integer getTotal_price() {
return total_price;
}
public void setTotal_price(Integer total_price) {
this.total_price = total_price;
}
}
detail订单明细类代码如下:
package com.spring.model; /**
* 商品明细表
* @author Administrator
*
*/
public class Detail {
//ID
private Integer detailId;
//外键 暂时可以忽略
private Integer orderId;
public Integer getDetailId() {
return detailId;
}
public void setDetailId(Integer detailId) {
this.detailId = detailId;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
//商品数量
private Integer quantity;
//商品数量
private String itemName; }
5.在service中定义一个接口并且实现它
OrderService代码如下:
package com.spring.service; import com.spring.model.Detail;
import com.spring.model.Order; public interface OrderService {
//插入订单和订单明细
public void saveOrderAndDetail(Order order,Detail detail);
}
OrderServiceImp代码如下:
package com.spring.service; import org.springframework.transaction.annotation.Transactional; import com.spring.dao.OrderDaoImp;
import com.spring.dao.detailDaoImp;
import com.spring.model.Detail;
import com.spring.model.Order; /**
* 服务层 使用注解来实现事务管理
*
* @author Administrator
*
*/ public class OrderServiceImp implements OrderService {
// 注入两个对象
public OrderDaoImp OrderDaoImp; public detailDaoImp detailDaoImp; @Transactional
@Override
// 如果加上@Transaction时,方法执行有异常,整个事务数据都会回滚,数据库中不会存在有数据。
public void saveOrderAndDetail(Order order, Detail detail) {
OrderDaoImp.saveOrder(order);
/**
* 如果不加@transaction时有异常存在,OrderDaoImp.saveOrder(order)方法将会执行。
* 但detailDaoImp.saveDetail(detail)不会执行
**/
int i = 100 / 0;
detailDaoImp.saveDetail(detail); } public OrderDaoImp getOrderDaoImp() {
return OrderDaoImp;
} public void setOrderDaoImp(OrderDaoImp orderDaoImp) {
OrderDaoImp = orderDaoImp;
} public detailDaoImp getDetailDaoImp() {
return detailDaoImp;
} public void setDetailDaoImp(detailDaoImp detailDaoImp) {
this.detailDaoImp = detailDaoImp;
} }
6.在util包中定义一个通知方法类
package com.spring.util;
public class SeizedAdvice {
/**
* 定义通知
*/
public void beforeAdvice(){
System.out.println("——————我是前置通知————————");
}
public void afterAdvice(){
System.out.println("------我是后置通知-------");
}
public void afterReturningAdvice(Object object){
System.out.println("————————我是返回后通知——————————"+object.toString());
}
public void afterThrowingAdvice(IllegalAccessError illegalAccessError){
System.out.println("--------我是异常返回异常返回通知---------"+illegalAccessError.toString());
}
}
7.在test中定义个测试类,用于测试
package com.test; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.spring.model.Detail;
import com.spring.model.Order;
import com.spring.service.OrderServiceImp; public class Test { public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
OrderServiceImp imp=(OrderServiceImp)applicationContext.getBean("OrderServiceImp"); Order order=new Order();
order.setTotal_price(699);
Detail detail=new Detail();
detail.setItemName("牙刷");
detail.setQuantity(3);
detail.setOrderId(4);
imp.saveOrderAndDetail(order,detail); }
}
8.最后就是我们的配置文件和数据库中的两张表
Spring bean.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: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/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 定义数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/jerry" />
<property name="username" value="root" />
<property name="password" value="1234" />
</bean> <!-- 事务管理方式注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager" /> <!-- 配置数据 proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。
如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用-->
<aop:config proxy-target-class="true">
<!-- 切 面-->
<aop:aspect id="myAspect" ref="SeizedAdvice">
<!-- 切 点-->
<aop:pointcut expression="execution(* com.spring.service.OrderServiceImp.*(..))"
id="myPointCut" />
<aop:before pointcut-ref="myPointCut" method="beforeAdvice" />
<aop:after pointcut-ref="myPointCut" method="afterAdvice" />
</aop:aspect>
</aop:config> <!-- 定义事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- 定义我们所需的bean -->
<bean id="SeizedAdvice" class="com.spring.util.SeizedAdvice"></bean> <bean id="OrderServiceImp" class="com.spring.service.OrderServiceImp">
<property name="detailDaoImp" ref="detailDaoImp"></property>
<property name="OrderDaoImp" ref="OrderDaoImp"></property>
</bean> <bean id="detailDaoImp" class="com.spring.dao.detailDaoImp">
<property name="dataSource" ref="dataSource" />
</bean> <bean id="OrderDaoImp" class="com.spring.dao.OrderDaoImp">
<property name="dataSource" ref="dataSource" />
</bean> </beans>
9. 数据库设计
detail(订单明细表 detail_id 订单明细ID,item_name 商品名称,quantity 订单数量 ,order_id 外键 暂时不用管这个属性)

Order(订单表,order_id 订单id,total_price 总金额)

10. 没有加@transaction测试如下:

这就会造成数据错误,不符合事务管理要求。加上@transaction再次测试如下图;

Spring 使用注解对事务控制详解与实例的更多相关文章
- 【Spring】——声明式事务配置详解
项目中用到了spring的事务: @Transactional(rollbackFor = Exception.class, transactionManager = "zebraTrans ...
- spring事务管理(详解和实例)
原文地址: 参考地址:https://blog.csdn.net/yuanlaishini2010/article/details/45792069 写这篇博客之前我首先读了<Spring in ...
- spring基于注解的事务控制
pom配置: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http ...
- Spring学习(十九)----- Spring的五种事务配置详解
前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. ...
- django后台使用MySQL情况下的事务控制详解
写在前面: 默认情况下django会把autocommit设置为“1”也就是说所针对数据库的每一次操作都会被做成“单独”的一个事务:这样的处理好处就在于它方便, 在编程的时候可以少写一些代码,比如我们 ...
- 注解@PostConstruct与@PreDestroy详解及实例
Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作.此文主要说明@PostConstru ...
- Java---JUnita、注解与类加载器详解以及实例
JUnit软件测试技术(工具) 在项目中建立专门用户测试的包结构. 在Junit中,通过@Test注解,可以运行一个方法. ★ Junit注解说明 使用了@Test注解应该满足以下条件: 1) 必须是 ...
- (转)Spring事务管理详解
背景:之前一直在学习数据库中的相关事务,而忽略了spring中的事务配置,在阿里面试时候基本是惨败,这里做一个总结. 可能是最漂亮的Spring事务管理详解 https://github.com/Sn ...
- 可能是最漂亮的Spring事务管理详解
Java面试通关手册(Java学习指南):https://github.com/Snailclimb/Java_Guide 微信阅读地址链接:可能是最漂亮的Spring事务管理详解 事务概念回顾 什么 ...
随机推荐
- 一维滑动窗口(SlidingWindow)
滑动窗口(Sliding Window)问题经常使用快慢指针(slow, fast pointer)[0, slow) 的区域为滑动窗口已经探索过的区域[slow, fast]的区域为滑动窗口正在探索 ...
- 一句话教你分清楚UML组合聚合和联系!
组合:组合后的实体消失,则所有构成实体的部件都无意义,可以理解为不能独立存在 定义: 与聚合相比,组合描述的是这样的关联关系,部分离开整体后就没有实际意义了.所以我们说组合是一种很强的关联关系. 例子 ...
- 2019年2月5日训练日记关于int字节数,long int 字节数的讨论
今天做到了个非常有意思的题目,是关于int最大最小值.用sizeof(int)查寻,返回四个字节,4个字节计算应该是4*8=32位,其中一位为符号位,且最高为不能为2所以应该减一,2^31-1=214 ...
- CF思维联系--CodeForces -214C (拓扑排序+思维+贪心)
ACM思维题训练集合 Furik and Rubik love playing computer games. Furik has recently found a new game that gre ...
- python(while 循环语句)
一.循环语句 1.while 循环 当我们在 python 中需要重复执行一些动作的时候,这时我们就要用到循环 while 循环的结构,当条件成立的时候,就会执行里面的代码 while 循环不断的运行 ...
- 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析
开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...
- Proteus传感器+气体浓度检测的报警方式控制仿真
Proteus传感器+气体浓度检测的报警方式控制仿真 目录 Proteus传感器+气体浓度检测的报警方式控制仿真 1 实验意义理解 2 主要实验器件 3 实验参考电路 4 实验中的问题思考 4.1 实 ...
- 【Hadoop离线基础总结】linux基础增强
linux基础增强 查找命令 grep命令 (print lines matching a pattern) 概述: grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打 ...
- [acdream_oj1732]求1到n的最小公倍数(n<=1e8)
题意:如标题 思路:如果n在10^6以内则可以用o(nlogn)的暴力,题目给定的是n<=1e8,暴力显然是不行的,考虑到1到n的最小公倍数可以写成2^p1*3^p2*5^p3*...这种素数的 ...
- Django使用channel实现websocket
channel 什么是channel? channel是第三方工具包,对于不支持websocket协议的框架可以借助此包实现websocket 安装 终端安装: pip3 install channe ...