09 Spring 事務(wù)管理(@Transactional)基本使用

轉(zhuǎn)載請注明來源 賴賴的博客

導(dǎo)語

只要你肯再堅持一會兒衣式,就會發(fā)現(xiàn)世界如此簡單谁不。

事務(wù)管理在持久層(數(shù)據(jù)庫)操作中是不可或缺的诅妹,其主要目的是為了保證操作的完整性票髓。
而Spring提供了強大的聲明式事務(wù)管理的方式疼进,其實現(xiàn)原理是采用了AOP對方法進行增強薪缆,使用起來非常方便,再也不用自己去管理事務(wù)(TRANSACTION)

實例

項目工程目錄結(jié)構(gòu)和代碼獲取地址

獲取地址(版本Log將會注明每一個版本對應(yīng)的課程)

https://github.com/laiyijie/SpringLearning

目錄結(jié)構(gòu)&數(shù)據(jù)庫

工程目錄結(jié)構(gòu)
目錄結(jié)構(gòu)
數(shù)據(jù)庫
數(shù)據(jù)庫

創(chuàng)建語句:

CREATE TABLE account (
    username varchar(45) NOT NULL,
    password varchar(45) NOT NULL,
    name varchar(45) NOT NULL,
    create_time bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE account
ADD PRIMARY KEY (username);

CREATE TABLE `pocket` (
  `username` varchar(45) NOT NULL,
  `current_money` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `pocket`
  ADD PRIMARY KEY (`username`);

運行工程

運行方式
  • 右鍵App.java
  • Run as
  • Java Application
運行結(jié)果

Exception in thread "main" java.lang.RuntimeException: lailai

數(shù)據(jù)庫新增兩條記錄:

  • account表中新增一條
account表新增數(shù)據(jù)
  • pocket表中新增一條
pocket表新增數(shù)據(jù)

項目詳解

App.java

package me.laiyijie.demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import me.laiyijie.demo.service.UserService;

public class App {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");

        UserService service = context.getBean(UserService.class);
        
        service.createAccount("laiyijie", "123123", "lai");
        
        service.createAccount("lailai", "123123", "lai");
        
        context.close();
    }

}  

有兩條createAccount語句伞广,卻只產(chǎn)生了一個賬號拣帽!問題肯定出現(xiàn)在createAccount方法中

我們來具體看下UserService 的實現(xiàn)類

UserServiceImpl.java

package me.laiyijie.demo.service;

import java.sql.Connection;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private BasicDataSource dataSource;

    @Transactional
    public void createAccount(String username, String password, String name) throws Exception {

        Connection connection = DataSourceUtils.getConnection(dataSource);

        connection.createStatement().execute("INSERT INTO account (username, password, name,create_time) VALUES('"
                + username + "','" + password + "','" + name + "','" + System.currentTimeMillis() + "')");

        if (username == "lailai") {
            throw new RuntimeException("lailai");
        }

        connection.createStatement()
                .execute("INSERT INTO pocket (username,current_money) VALUES('" + username + "','" + 0 + "')");

    }

}

函數(shù)執(zhí)行過程:

  • 通過DataSourceUtils.getConnectiondataSource中獲取connection

Connection connection = DataSourceUtils.getConnection(dataSource);

  • 執(zhí)行插入account表的insert語句

connection.createStatement().execute("INSERT INTO account (username, password, name,create_time) VALUES('" + username + "','" + password + "','" + name + "','" + System.currentTimeMillis() + "')");

  • 判斷是否用戶名為lailai,是的話拋出運行時錯誤

if (username == "lailai") {
throw new RuntimeException("lailai");
}

  • 執(zhí)行插入pocket表的insert語句

connection.createStatement().execute("INSERT INTO pocket (username,current_money) VALUES('" + username + "','" + 0 + "')");

那么很明顯嚼锄,在main函數(shù)中執(zhí)行第二次createAccount的過程中减拭,拋出了錯誤,而拋出錯誤的時間是在執(zhí)行完插入account表之后区丑!

理論上講拧粪,在拋錯之前的所有語句都應(yīng)該被執(zhí)行,也就是說沧侥,我們應(yīng)該向數(shù)據(jù)庫中插入了三行數(shù)據(jù)可霎,兩條account數(shù)據(jù),一條pocket數(shù)據(jù)宴杀,然而卻只有一條account數(shù)據(jù)和一條pocket數(shù)據(jù)癣朗。

讓我們看看lailai這條account數(shù)據(jù)去哪兒了。

@Transactional 注解(spring的事務(wù)管理)

細心的讀者可以發(fā)現(xiàn)旺罢,在createAccount函數(shù)之前我們增加了一個注解@Transactional旷余,這個是Spring事務(wù)管理的聲明,其寓意為:

當(dāng)執(zhí)行createAccount的時候扁达,將創(chuàng)建一個事務(wù)正卧,函數(shù)執(zhí)行成功,則正常提交跪解,當(dāng)函數(shù)拋出RuntimeExeption的時候則回滾

這里有幾個隱含的條件非常重要:

  • 數(shù)據(jù)庫連接的獲取一定要通過 DataSourceUtils.getConnection 來獲取炉旷。每一個事務(wù)都是綁定在一個連接上的,如果還是通過 datasource.getConnection方法獲取連接則有可能是獲取到別的連接(由于連接池的存在)而DataSourceUtils.getConnection 獲取的連接是當(dāng)前事務(wù)的連接
  • 只有將異常拋出才能產(chǎn)生回滾,如果使用try catch處理了異常是不能回滾的
  • 默認情況下只有RuntimeException的拋出會產(chǎn)生回滾窘行,如果需要自行定義可以回滾的異常骏啰,可以通過增加RollbackFor屬性:
    • @Transactional(rollbackFor={Exception.class})
      
  • 如果使用mysql數(shù)據(jù)庫,請不要用 MyISAM引擎抽高,因為不支持事務(wù),請使用InnoDB引擎

說了這么多限制透绩,那么到底應(yīng)該如何在Spring中配置事務(wù)呢:

root-context.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:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
        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-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


    <bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://127.0.0.1:3306/myspring"
        p:username="test" p:password="o34rWayJPPHgudtL" />

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="mysqlDataSource" />
        
    <tx:annotation-driven transaction-manager="transactionManager" />

    <context:component-scan base-package="me.laiyijie.demo"></context:component-scan>

</beans>  

增加了兩個配置:

  • 配置TransactionManager

      <bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
      p:dataSource-ref="mysqlDataSource" />  
    
  • 開啟注解驅(qū)動

      <tx:annotation-driven transaction-manager="transactionManager" />
    

pom.xml

<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>me.laiyijie</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>



    </dependencies>
</project>

無需增加額外依賴翘骂! spring-context中自帶!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帚豪,一起剝皮案震驚了整個濱河市碳竟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狸臣,老刑警劉巖莹桅,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烛亦,居然都是意外死亡诈泼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門煤禽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铐达,“玉大人,你說我怎么就攤上這事檬果∥退铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵选脊,是天一觀的道長杭抠。 經(jīng)常有香客問我,道長恳啥,這世上最難降的妖魔是什么偏灿? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮角寸,結(jié)果婚禮上菩混,老公的妹妹穿的比我還像新娘。我一直安慰自己扁藕,他們只是感情好沮峡,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亿柑,像睡著了一般邢疙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天疟游,我揣著相機與錄音呼畸,去河邊找鬼。 笑死颁虐,一個胖子當(dāng)著我的面吹牛蛮原,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播另绩,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼儒陨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笋籽?” 一聲冷哼從身側(cè)響起蹦漠,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎车海,沒想到半個月后笛园,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡侍芝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年研铆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片州叠。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚜印,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出留量,到底是詐尸還是另有隱情,我是刑警寧澤楼熄,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布忆绰,位于F島的核電站,受9級特大地震影響可岂,放射性物質(zhì)發(fā)生泄漏错敢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一缕粹、第九天 我趴在偏房一處隱蔽的房頂上張望稚茅。 院中可真熱鬧,春花似錦平斩、人聲如沸亚享。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欺税。三九已至侈沪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晚凿,已是汗流浹背亭罪。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留歼秽,地道東北人应役。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像燥筷,于是被迫代替她去往敵國和親扛吞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理荆责,服務(wù)發(fā)現(xiàn),斷路器亚脆,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,822評論 6 342
  • application的配置屬性做院。 這些屬性是否生效取決于對應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,374評論 1 27
  • 這些屬性是否生效取決于對應(yīng)的組件是否聲明為 Spring 應(yīng)用程序上下文里的 Bean(基本是自動配置的),為一個...
    發(fā)光的魚閱讀 1,426評論 0 14
  • 今天下午的戶外活動是親近大自然之小溪玩水樂趣多濒持。這是一條神奇的小溪键耕,這里有溫泉,可以泡泡腳柑营,這里有小魚小蝦屈雄,可以體...
    蕭賀閱讀 269評論 0 0