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事务管理详解 事务概念回顾 什么 ...
随机推荐
- MYSQL 排序和分组
一.MYSQL 中有两种排序方式: 1:通过有序索引顺序扫描直接返回有序数据,这种方式在使用explain 分析查询的时候显示为Using Index ,不需要额外的排序,操作效率较高. 2: 是通过 ...
- 8) drf 三大认证 认证 权限 频率
一.三大认证功能分析 1)APIView的 dispath(self, request, *args, **kwargs) 2)dispath方法内 self.initial(request, *ar ...
- XCTF练习题-WEB-webshell
XCTF练习题-WEB-webshell 解题步骤: 1.观察题目,打开场景 2.根据题目提示,这道题很有可能是获取webshell,再看描述,一句话,基本确认了,观察一下页面,一句话内容,密码为sh ...
- Shell脚本(三)重定向
先上一张图: 代码如下: #!/bin/bash echo "hello world" echo `ls +` 运行结果如下: PS: 1. 如果想同时将数据重定向到文件和stdo ...
- string操作大全
1. string to int && int to string 2. 整数1转换成字符串"001" int sprintf ( char * str, cons ...
- Python爬虫(二)爬百度贴吧楼主发言
爬取电影吧一个帖子里的所有楼主发言: # python2 # -*- coding: utf-8 -*- import urllib2 import string import re class Ba ...
- PLAI那些事_06 FAE
没有了with表达,with,exp,body的id换成exp的lambda函数,从而可以没有with来进行实现.即,{with {id exp} body}换成了{{fun {id} body} e ...
- windows脱密码总结
方式1:通过SAM数据库获得本地用户HASH sam文件:是用来存储本地用户账号密码的文件的数据库system文件:里面有对sam文件进行加密和加密的密钥 利用方式: 导出sam和system: re ...
- POJ3279(开关后续)
描述: 一个\(n*m的矩阵,每个格子有0和1两种状态.每次可以翻一个格子,并且此格子的上下左右都要被翻.\) \(目标状态应该全为0,求最少翻的次数,输出最小字典序的方案\) 这儿可就麻烦了啊,开关 ...
- D. Count the Arrays 计数题
D. Count the Arrays 也是一个计数题. 题目大意: 要求构造一个满足题意的数列. \(n\) 代表数列的长度 数列元素的范围 \([1,m]\) 数列必须有且仅有一对相同的数 存在一 ...