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包 鏈接如下:https://www.cnblogs.com/ysource/p/12956273.html jar在文章中
2.在src目錄下新建5個包 如圖
dao :數據連接層,主要用於存放對數據進行操作的類
model:模型層,主要用於存放實體類
service:服務層,主要用於對數據連接層進行操作的一些服務類。
util:工具類,主要用於存儲工具方法
test:用於測試類
3.在dao數據連接層,建立裏與數據庫操作的類與對應的接口 (Order 訂單 ,detail訂單明細)
3.1 定義detailDao接口 代碼如下:
1 package com.spring.dao;
2
3 import com.spring.model.Detail;
4 import com.spring.model.Order;
5
6 public interface detailDao {
7 //保存訂單明細
8 public void saveDetail(Detail detail);
9
10
11
12 }
3.2 定義OrderDao接口 代碼如下:
1 package com.spring.dao;
2
3 import com.spring.model.Order;
4
5 public interface OrderDao {
6 //保存訂單
7 public void saveOrder(Order order);
8
9
10
11 }
3.3 實現以上接口
detailDaoImp 代碼如下:
1 package com.spring.dao;
2
3 import javax.sql.DataSource;
4
5 import org.springframework.jdbc.core.JdbcTemplate;
6
7 import com.spring.model.Detail;
8 import com.spring.model.Order;
9
10 public class detailDaoImp implements detailDao {
11
12 private DataSource dataSource;
13 private JdbcTemplate jdbcTemplate;
14
15 public void setDataSource(DataSource dataSource) {
16 this.dataSource = dataSource;
17 this.jdbcTemplate = new JdbcTemplate(dataSource);
18 }
19 //保存訂單明細
20 public void saveDetail(Detail detail) {
21 String SQL = "insert into t_detail values(null,?,?,?))";
22 jdbcTemplate.update(SQL, new Object[] { detail.getItemName(),detail.getQuantity(),detail.getOrderId() });
23 System.out.println("Insert detail success!");
24 }
25
26 }
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訂單類代碼如下:
1 package com.spring.model;
2
3 /*
4 * 訂單表
5 */
6 public class Order {
7 //訂單編號
8 private Integer order_id;
9 //訂單總金額
10 private Integer total_price;
11 public Integer getOrder_id() {
12 return order_id;
13 }
14 public void setOrder_id(Integer order_id) {
15 this.order_id = order_id;
16 }
17 public Integer getTotal_price() {
18 return total_price;
19 }
20 public void setTotal_price(Integer total_price) {
21 this.total_price = total_price;
22 }
23 }
detail訂單明細類代碼如下:
1 package com.spring.model;
2
3 /**
4 * 商品明細表
5 * @author Administrator
6 *
7 */
8 public class Detail {
9 //ID
10 private Integer detailId;
11 //外鍵 暫時可以忽略
12 private Integer orderId;
13 public Integer getDetailId() {
14 return detailId;
15 }
16 public void setDetailId(Integer detailId) {
17 this.detailId = detailId;
18 }
19 public Integer getOrderId() {
20 return orderId;
21 }
22 public void setOrderId(Integer orderId) {
23 this.orderId = orderId;
24 }
25 public Integer getQuantity() {
26 return quantity;
27 }
28 public void setQuantity(Integer quantity) {
29 this.quantity = quantity;
30 }
31 public String getItemName() {
32 return itemName;
33 }
34 public void setItemName(String itemName) {
35 this.itemName = itemName;
36 }
37 //商品數量
38 private Integer quantity;
39 //商品數量
40 private String itemName;
41
42 }
5.在service中定義一個接口並且實現它
OrderService代碼如下:
1 package com.spring.service;
2
3 import com.spring.model.Detail;
4 import com.spring.model.Order;
5
6 public interface OrderService {
7 //插入訂單和訂單明細
8 public void saveOrderAndDetail(Order order,Detail detail);
9 }
OrderServiceImp代碼如下:
1 package com.spring.service;
2
3 import org.springframework.transaction.annotation.Transactional;
4
5 import com.spring.dao.OrderDaoImp;
6 import com.spring.dao.detailDaoImp;
7 import com.spring.model.Detail;
8 import com.spring.model.Order;
9
10 /**
11 * 服務層 使用註解來實現事務管理
12 *
13 * @author Administrator
14 *
15 */
16
17 public class OrderServiceImp implements OrderService {
18 // 注入兩個對象
19 public OrderDaoImp OrderDaoImp;
20
21 public detailDaoImp detailDaoImp;
22
23 @Transactional
24 @Override
25 // 如果加上@Transaction時,方法執行有異常,整個事務數據都會回滾,數據庫中不會存在有數據。
26 public void saveOrderAndDetail(Order order, Detail detail) {
27 OrderDaoImp.saveOrder(order);
28 /**
29 * 如果不加@transaction時有異常存在,OrderDaoImp.saveOrder(order)方法將會執行。
30 * 但detailDaoImp.saveDetail(detail)不會執行
31 **/
32 int i = 100 / 0;
33 detailDaoImp.saveDetail(detail);
34
35 }
36
37 public OrderDaoImp getOrderDaoImp() {
38 return OrderDaoImp;
39 }
40
41 public void setOrderDaoImp(OrderDaoImp orderDaoImp) {
42 OrderDaoImp = orderDaoImp;
43 }
44
45 public detailDaoImp getDetailDaoImp() {
46 return detailDaoImp;
47 }
48
49 public void setDetailDaoImp(detailDaoImp detailDaoImp) {
50 this.detailDaoImp = detailDaoImp;
51 }
52
53 }
6.在util包中定義一個通知方法類
1 package com.spring.util;
2
3 public class SeizedAdvice {
4 /**
5 * 定義通知
6 */
7
8 public void beforeAdvice(){
9 System.out.println("——————我是前置通知————————");
10
11 }
12 public void afterAdvice(){
13 System.out.println("------我是後置通知-------");
14
15 }
16 public void afterReturningAdvice(Object object){
17 System.out.println("————————我是返回後通知——————————"+object.toString());
18
19 }
20 public void afterThrowingAdvice(IllegalAccessError illegalAccessError){
21 System.out.println("--------我是異常返回異常返回通知---------"+illegalAccessError.toString());
22
23
24 }
25
26
27
28 }
7.在test中定義個測試類,用於測試
1 package com.test;
2
3 import org.springframework.context.ApplicationContext;
4 import org.springframework.context.support.ClassPathXmlApplicationContext;
5
6 import com.spring.model.Detail;
7 import com.spring.model.Order;
8 import com.spring.service.OrderServiceImp;
9
10 public class Test {
11
12 public static void main(String[] args) {
13 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
14 OrderServiceImp imp=(OrderServiceImp)applicationContext.getBean("OrderServiceImp");
15
16 Order order=new Order();
17 order.setTotal_price(699);
18 Detail detail=new Detail();
19 detail.setItemName("牙刷");
20 detail.setQuantity(3);
21 detail.setOrderId(4);
22 imp.saveOrderAndDetail(order,detail);
23
24 }
25 }
8.最後就是我們的配置文件和數據庫中的兩張表
Spring bean.xml代碼如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
4 xmlns:aop="http://www.springframework.org/schema/aop"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
7 http://www.springframework.org/schema/tx
8 http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
9 http://www.springframework.org/schema/aop
10 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
11 <!-- 定義數據源 -->
12 <bean id="dataSource"
13 class="org.springframework.jdbc.datasource.DriverManagerDataSource">
14 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
15 <property name="url" value="jdbc:mysql://localhost:3306/jerry" />
16 <property name="username" value="root" />
17 <property name="password" value="1234" />
18 </bean>
19
20
21
22 <!-- 事務管理方式註解驅動 -->
23 <tx:annotation-driven transaction-manager="transactionManager" />
24
25 <!-- 配置數據 proxy-target-class屬性值決定是基於接口的還是基於類的代理被創建。
26 如果proxy-target-class 屬性值被設置爲true,那麼基於類的代理將起作用-->
27 <aop:config proxy-target-class="true">
28 <!-- 切 面-->
29 <aop:aspect id="myAspect" ref="SeizedAdvice">
30 <!-- 切 點-->
31 <aop:pointcut expression="execution(* com.spring.service.OrderServiceImp.*(..))"
32 id="myPointCut" />
33 <aop:before pointcut-ref="myPointCut" method="beforeAdvice" />
34 <aop:after pointcut-ref="myPointCut" method="afterAdvice" />
35 </aop:aspect>
36 </aop:config>
37
38
39 <!-- 定義事務管理器 -->
40 <bean id="transactionManager"
41 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
42 <property name="dataSource" ref="dataSource" />
43 </bean>
44
45 <!-- 定義我們所需的bean -->
46 <bean id="SeizedAdvice" class="com.spring.util.SeizedAdvice"></bean>
47
48 <bean id="OrderServiceImp" class="com.spring.service.OrderServiceImp">
49 <property name="detailDaoImp" ref="detailDaoImp"></property>
50 <property name="OrderDaoImp" ref="OrderDaoImp"></property>
51 </bean>
52
53 <bean id="detailDaoImp" class="com.spring.dao.detailDaoImp">
54 <property name="dataSource" ref="dataSource" />
55 </bean>
56
57 <bean id="OrderDaoImp" class="com.spring.dao.OrderDaoImp">
58 <property name="dataSource" ref="dataSource" />
59 </bean>
60
61 </beans>
9. 數據庫設計
detail(訂單明細表 detail_id 訂單明細ID,item_name 商品名稱,quantity 訂單數量 ,order_id 外鍵 暫時不用管這個屬性)
Order(訂單表,order_id 訂單id,total_price 總金額)