spring學習筆記(21)程式設計式事務配置,service層概念引入
訪問資料庫事務匯入
public <E> E add(Object object) {
return (E) getSessionFactory().openSession().save(object);
}
通過直接開啟session而後儲存物件、查詢資料等操作,是沒有事務的。而如果我們的專案規模變大,業務邏輯日益複雜,我們在一個方法中進行大量的資料庫操作,而沒有事務管理的話,一旦中間哪一個操作環節出錯,後果是嚴重的。比如,一個使用者通過支付寶轉100塊到銀行賬戶,於是使用者的100塊先轉到了銀行,但這時資料庫異常中斷,銀行無法把100塊轉給使用者賬戶,這時事務又沒有回滾,那麼可能使用者的100塊就白白損失掉了。
在spring中,有多種方式可以進行我們的事務配置,比如我們可以直接修改上面的方法,加上事務:
public <E> E add(Object object) {
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
E id = (E) session.save(object);
tx.commit();
return id;
}
這樣,我們就能為我們的add方法加上簡單的事務了。
多資料庫操作事務配置——引入Service層
但這樣的話我們針對的只是dao層add這個方法,但在實際中,我們可能需要同時控制大量DAO的方法在同一個事務中,為此,我們可以建立service層來統一進行我們的業務邏輯處理。比如我們根據需求,需要先獲取使用者id,並修改使用者名稱稱,這裡設計兩個資料庫操作,但我們在同一個service類方法中完成。
程式設計式事務模板類:TransactionTemplate
概念
在下例中,我們依然使用程式設計式事務,spring為此專門提供了模板類TransactionTemplate來滿足我們的需求。TransactionTemplate是執行緒安全的,也即是說,我們可以在多個業務類中共享同一個TransactionTemplate例項進行事務管理。
常用屬性
TransactionTemplate有很多常用的屬性如:
1. isolationLevel:設定事務隔離級別
2. propagationBehavior:設定我們的事務傳播行為
3. readOnly:設定為只讀事務,即資料寫操作會失敗
4. timeout:設定連結過期時間,-1和預設為無超時限制
5. transactionManager:它是我們的IOC容器配置時的必要屬性,設定我們的事務管理物件。在本例中用到hibernate,為HibernateTransactionManager。
核心方法
TransactionTemplate類在呼叫時主要用到的方法為execute(TransactionCallback
action)。
有返回值的回撥介面
其中TransactionCallback為我們的回撥介面,它只有一個方法:
T doInTransaction(TransactionStatus status),這個方法內是有事務的。通常我們的資料庫查詢操作就在這個方法裡完成。
方法入參TransactionStatus介面
doInTransaction方法的唯一入參是TransactionStatus,它常用於檢視我們當前的事務狀態,它有兩個常用的方法:
1. createSavepoint():建立一個記錄點。
2. rollbackToSavepoint(savepoint):將事務回滾到特定記錄點,這樣從回滾處到記錄點範圍內所有的資料庫操作都會失效。
無返回值的介面TransactionCallback
另外,doInTransaction是有返回值的,如果我們不需要返回值,我們可以使用TransactionCallback介面的一個子類TransactionCallbackWithoutResult,它對應的抽象方法doInTransactionWithoutResult(TransactionStatus status)是沒有返回值的。
例項演示
下面開始我們的例項演示
1. service層配置
public class MyaseServiceImpl implements MyBaseService{
private MyBaseDao myBaseDao;
private TransactionTemplate transactionTemplate;
@Override//測試方法
public void queryUpdateUser(final Integer id,final String newName) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
User user = myBaseDao.queryUnique(User.class, id);//根據id獲取使用者
System.out.println(user);
user.setName(newName);//修改名稱
myBaseDao.update(user);//更新資料庫
System.out.println(user);
}
});
/*下面的方法是由返回值的,在這裡我們假設為User。
User user = transactionTemplate.execute(new TransactionCallback<User>() {
@Override
public User doInTransaction(TransactionStatus status) {
User user = myBaseDao.queryUnique(User.class, id);
System.out.println(user);
user.setName(newName);
myBaseDao.update(user);
System.out.println(user);
return user;
}
});
*/
}
public void setMyBaseDao(MyBaseDao myBaseDao) {//set屬性注入
this.myBaseDao = myBaseDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
}
2. DAO層配置
對應的DAO層類和部分方法如下所示:
public class MyBaseDaoImpl implements MyBaseDao{
private SessionFactory sessionFactory;
private Session getCurrentSession (){//根據引數來選擇建立一個新的session還是返回當前執行緒的已有session
return sessionFactory.getCurrentSession();
}
@Override
public <E> E queryUnique(Class<E> clazz, Integer entityId) {//查詢唯一的物件
return (E) getCurrentSession().get(clazz, entityId);
}
@Override
public void update(Object object) {//更新物件
getCurrentSession().update(object);
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
3. Spring容器配置Bean依賴關係
如果對於Hibernate不太理解,可以先不管我們的方法實現原理,只需要知道對應的方法實現了什麼功能即可。在這裡。接下來我們要配置我們的spring容器,主要完成Bean之間的依賴配置:
<bean id="myBaseDao" class="com.yc.dao.MyBaseDaoImpl" >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="myBaseServiceImpl" class="com.yc.service.MyBaseServiceImpl" >
<property name="myBaseDao" ref="myBaseDao" />
<property name="transactionTemplate" ref="transactionTemplate" />
</bean>
關於資料來源和sessionFactory的配置例項如下:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"><!-- 設定為close使Spring容器關閉同時資料來源能夠正常關閉,以免造成連線洩露 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/yc" />
<property name="username" value="yc" />
<property name="password" value="yc" />
<property name="defaultReadOnly" value="false" /><!-- 設定為只讀狀態,配置讀寫分離時,讀庫可以設定為true
在連線池建立後,會初始化並維護一定數量的資料庫安連線,當請求過多時,資料庫會動態增加連線數,
當請求過少時,連線池會減少連線數至一個最小空閒值 -->
<property name="initialSize" value="5" /><!-- 在啟動連線池初始建立的資料庫連線,預設為0 -->
<property name="maxActive" value="15" /><!-- 設定資料庫同一時間的最大活躍連線預設為8,負數表示不閒置 -->
<property name="maxIdle" value="10"/><!-- 在連線池空閒時的最大連線數,超過的會被釋放,預設為8,負數表示不閒置 -->
<property name="minIdle" value="2" /><!-- 空閒時的最小連線數,低於這個數量會建立新連線,預設為0 -->
<property name="maxWait" value="10000" /><!-- 連線被用完時等待歸還的最大等待時間,單位毫秒,超出時間拋異常,預設為無限等待 -->
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<!-- MySQL的方言 -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="javax.persistence.validation.mode">none</prop>
<!-- 必要時在資料庫新建所有表格 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="current_session_context_class">thread</prop>
<!-- <prop key="hibernate.format_sql">true</prop> -->
</props>
</property>
<property name="packagesToScan" value="com.yc.model" />
</bean>
4. 測試方法和結果分析
配置完成後,就可以進行我們的測試了。在這裡,我用到了Junit測試元件
public class Test1 {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/spring-datasource.xml");
MyBaseServiceImpl myBaseServiceImpl = (MyBaseServiceImpl) ac.getBean("myBaseServiceImpl");
myBaseServiceImpl.queryUpdateUser(1, "newName");//在這裡呼叫我們的service層方法
}
}
呼叫測試方法,我們會看到控制檯輸出如下相關資訊:
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtaining JDBC connection
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtained JDBC connection
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - begin————————這裡我們的事務開始了
DEBUG: org.hibernate.loader.Loader - Loading entity: [com.yc.model.User#1]——————————讀取id為1的使用者
DEBUG: org.hibernate.loader.Loader - Done entity load//完成裝載工作
User [id=1, name=zenghao]——————獲得了我們的User資訊
User [id=1, name=newName]——————完成了修改操作
DEBUG: org.springframework.orm.hibernate4.HibernateTransactionManager - Initiating transaction commit//初始化資料庫提交
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - committing————————這時候才完成了事務提交
觀察列印資訊,我們會發現我們像資料庫發出了兩次請求(分別為獲取和更新)但事務才提交了一次。說明這兩個請求在同一個事務中。這樣我們就能確保多個數據庫操作在同一個事務內完成,一旦中間出現異常,能立即回滾,取消前面的資料庫操作。
很多人都知道我們的mvc模式將後端業務分成了三層(DAO,service,controller),從這裡,我們也能略微看出DAO層和service層的功能職責了。DAO主要完成資料庫查詢的封裝,而Service層則呼叫DAO層的資料庫查詢方法來完成我們的業務邏輯處理
相關推薦
spring學習筆記(21)程式設計式事務配置,service層概念引入
訪問資料庫事務匯入 public <E> E add(Object object) { return (E) getSessionFactory().openSession().save(object); } 通過直接開啟sess
spring學習筆記(22)聲明式事務配置,readOnly無效寫無異常
lin top post 處理 ast cannot pro ever 也不會 在上一節內容中。我們使用了編程式方法來配置事務,這種優點是我們對每一個方法的控制性非常強。比方我須要用到什麽事務,在什麽位置假設出現異常須要回滾等。能夠進行非常細粒度的配置。
spring學習筆記(23)基於tx/aop配置切面增強事務
在上一篇文章中,我們使用了宣告式事務來配置事務,使事務配置從service邏輯處理中解耦出來。但它還存在一些缺點: 1. 我們只針對方法名的特定進行攔截,但無法利用方法簽名的其它資訊定位,如修飾符、返
spring學習筆記(3)——bean配置細節註意
collect 1.5 之前 ice ble person name return 引用 1. 一個bean引用另外一個bean 當Person類中有一個屬性是Car,那麽該如何配置呢 person: package com.zj.spring; public class
spring 宣告式事務配置,丟擲runtimeException異常不回滾
預設spring只在發生未被捕獲的runtimeexcetpion時才回滾。 最容易解決的辦法:程式碼級控制:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); try{ ..
Spring學習筆記三: 通過註解配置Bean
一、在 classpath 中掃描元件 元件掃描(component scanning): Spring 能夠從 classpath 下自動掃描, 偵測和例項化具有特定註解的元件. 特定元件包括: @Component: 基本註解, 標識了一個受 S
Spring學習筆記(一):眼見為實,先上一個簡單例子
概述 所謂眼見為實,Spring雖然是一個輕量級的框架,但涉及眾多的概念,理解起來並不容易,因此,先參考資料寫一個簡單的Demo,從中洞見Spring的大體工作流程,為後面深入學習做鋪墊。 本文的Demo很簡單:模擬圖書資料訪問服務,即向資料庫中新增圖書資訊,涉及IBoo
用Java+xml配置方式實現Spring資料事務(程式設計式事務)
一、用Java配置的方式 1、實體類: Role public class Role { private int id; private String roleName; private String note; @Override
Spring筆記(4) - Spring的程式設計式事務和宣告式事務詳解
一.背景 事務管理對於企業應用而言至關重要。它保證了使用者的每一次操作都是可靠的,即便出現了異常的訪問情況,也不至於破壞後臺資料的完整性。就像銀行的自助取款機,通常都能正常為客戶服務,但是也難免遇到操作過程中機器突然出故障的情況,此時,事務就必須確保出故障前對賬戶的操作不生效,就像使用者剛才完全沒有使用過取
Spring 學習筆記(七)—— 切入點表達式
service string 出現 targe || 參數 public 例如 語法 為了能夠靈活定義切入點位置,Spring AOP提供了多種切入點指示符。 execution———用來匹配執行方法的連接點
Python學習筆記21(讀取配置文件)
文件 class strong color () for 新的 -i .config 1、基本的讀取操作 -read(filename) 直接讀取文件內容 -sections() 得到所有的sectio
Linux學習筆記_shell程式設計之環境變數配置檔案
shell程式設計之環境變數配置檔案 https://www.imooc.com/learn/361 簡介:本課程是《Tony老師聊shell》系列課程的第三篇,為你帶來常用的Linux環境變數配置檔案的使用。對環境變數配置檔案的功能進行了詳解, 然後又介紹了其他環境變數配置檔案,包括登
Spring 程式設計式事務 宣告式事務
程式設計式事務通用類: import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.datasource.DataSourceTransactionManager
第十講:10.spring對事物的支援-程式設計式事務管理
轉賬業務 1,複製spring403-03 改名spring403:建立表結構,資料庫的引擎一定是InnoDB Create Table CREATE TABLE `t_account` (  
淺談spring事務管理的2種方式:程式設計式事務管理和宣告式事務管理;以及@Transactional(rollbackFor=Exception.class)註解用法
事務的概念,以及特性: 百度百科介紹: ->資料庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。 事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向資料的資源。通過
使用Spring程式設計式事務TransactionTemplate
使用場景 假如有一個專案設定了資料庫最大連線數為3,然後專案中提供了一個介面,介面中的一個方法會做以下邏輯處理:①首先在資料庫的某個表中查詢出一條記錄,②然後利用該條記錄的資料去調第三方的介面,然後第三方介面放回資料,③最後修改該條記錄的某個欄位的資料然後更新回資料庫。 假設有4個使
spring 程式設計式事務 (spring事務一)
配置檔案 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org
8.spring:事務管理(上):Spring的資料庫程式設計、程式設計式事務管理
Spring的資料庫程式設計 Spring框架提供了JDBC模板模式------>JdbcTemplate 簡化了開發,在開發中並不經常是使用 實際開發更多使用的是Hibernate和MyBatis 1).Spring JDBCp配置 如果使用Spring JDBC操作資料庫,要有
spring 原始碼學習筆記(二)事務管理
spring 事務管理會幫我們自動管理資料庫的事務,沒讀原始碼前覺得很神祕,讀了原始碼發現原理還是很簡單的。 本質上還是用的 jdbc 的事務管理。spring 在呼叫某個方法前,判斷是否需要事務,如果需要,則呼叫 con.setAutoCommit(false);//開
手寫Spring註解事務(利用AOP技術 + 註解 + Spring程式設計式事務)
1.參考下面的文章搭建一個無事務管理的SSM操作資料庫的框架 Spring 使用Druid資料來源 整合 Mybatis 2.AOP技術參考 AOP技術應用實現 3.第一步首先實現Sprin