国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

spring6-事務(wù)

這篇具有很好參考價(jià)值的文章主要介紹了spring6-事務(wù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1、JdbcTemplate

1.1、簡介

spring6-事務(wù),spring,java,spring,spring6,事務(wù),后端

Spring 框架對 JDBC 進(jìn)行封裝,使用 JdbcTemplate 方便實(shí)現(xiàn)對數(shù)據(jù)庫操作

1.2、準(zhǔn)備工作

①搭建子模塊

搭建子模塊:spring-jdbc-tx

②加入依賴

<dependencies>
    <!--spring jdbc  Spring 持久化層支持jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.2</version>
    </dependency>
    <!-- MySQL驅(qū)動 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    <!-- 數(shù)據(jù)源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.15</version>
    </dependency>
</dependencies>

③創(chuàng)建jdbc.properties

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false
jdbc.driver=com.mysql.cj.jdbc.Driver

④配置Spring的配置文件

beans.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"
       xsi:schemaLocation="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.xsd">

    <!-- 導(dǎo)入外部屬性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置數(shù)據(jù)源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置 JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 裝配數(shù)據(jù)源 -->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

</beans>

⑤準(zhǔn)備數(shù)據(jù)庫與測試表

CREATE DATABASE `spring`;

use `spring`;

CREATE TABLE `t_emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年齡',
  `sex` varchar(2) DEFAULT NULL COMMENT '性別',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.3、實(shí)現(xiàn)CURD
①裝配 JdbcTemplate

創(chuàng)建測試類,整合JUnit,注入JdbcTemplate

package com.atguigu.spring6;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

@SpringJUnitConfig(locations = "classpath:beans.xml")
public class JDBCTemplateTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
}
②測試增刪改功能
@Test
//測試增刪改功能
public void testUpdate(){
    //添加功能
	String sql = "insert into t_emp values(null,?,?,?)";
	int result = jdbcTemplate.update(sql, "張三", 23, "男");
    
    //修改功能
	//String sql = "update t_emp set name=? where id=?";
    //int result = jdbcTemplate.update(sql, "張三atguigu", 1);

    //刪除功能
	//String sql = "delete from t_emp where id=?";
	//int result = jdbcTemplate.update(sql, 1);
}
③查詢數(shù)據(jù)返回對象
public class Emp {

    private Integer id;
    private String name;
    private Integer age;
    private String sex;

    //生成get和set方法
    //......

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
//查詢:返回對象
@Test
public void testSelectObject() {
    //寫法一
//        String sql = "select * from t_emp where id=?";
//        Emp empResult = jdbcTemplate.queryForObject(sql,
//                (rs, rowNum) -> {
//                    Emp emp = new Emp();
//                    emp.setId(rs.getInt("id"));
//                    emp.setName(rs.getString("name"));
//                    emp.setAge(rs.getInt("age"));
//                    emp.setSex(rs.getString("sex"));
//                    return emp;
//                }, 1);
//        System.out.println(empResult);

    //寫法二
    String sql = "select * from t_emp where id=?";
    Emp emp = jdbcTemplate.queryForObject(sql,
                  new BeanPropertyRowMapper<>(Emp.class),1);
    System.out.println(emp);
}
④查詢數(shù)據(jù)返回list集合
@Test
//查詢多條數(shù)據(jù)為一個list集合
public void testSelectList(){
    String sql = "select * from t_emp";
    List<Emp> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Emp.class));
    System.out.println(list);
}
⑤查詢返回單個的值
@Test
//查詢單行單列的值
public void selectCount(){
    String sql = "select count(id) from t_emp";
    Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
    System.out.println(count);
}

2、聲明式事務(wù)概念

2.1、事務(wù)基本概念
①什么是事務(wù)

數(shù)據(jù)庫事務(wù)( transaction)是訪問并可能操作各種數(shù)據(jù)項(xiàng)的一個數(shù)據(jù)庫操作序列,這些操作要么全部執(zhí)行,要么全部不執(zhí)行,是一個不可分割的工作單位。事務(wù)由事務(wù)開始與事務(wù)結(jié)束之間執(zhí)行的全部數(shù)據(jù)庫操作組成。

②事務(wù)的特性

A:原子性(Atomicity)

一個事務(wù)(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。

C:一致性(Consistency)

事務(wù)的一致性指的是在一個事務(wù)執(zhí)行之前和執(zhí)行之后數(shù)據(jù)庫都必須處于一致性狀態(tài)。

如果事務(wù)成功地完成,那么系統(tǒng)中所有變化將正確地應(yīng)用,系統(tǒng)處于有效狀態(tài)。

如果在事務(wù)中出現(xiàn)錯誤,那么系統(tǒng)中的所有變化將自動地回滾,系統(tǒng)返回到原始狀態(tài)。

I:隔離性(Isolation)

指的是在并發(fā)環(huán)境中,當(dāng)不同的事務(wù)同時操縱相同的數(shù)據(jù)時,每個事務(wù)都有各自的完整數(shù)據(jù)空間。由并發(fā)事務(wù)所做的修改必須與任何其他并發(fā)事務(wù)所做的修改隔離。事務(wù)查看數(shù)據(jù)更新時,數(shù)據(jù)所處的狀態(tài)要么是另一事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會查看到中間狀態(tài)的數(shù)據(jù)。

D:持久性(Durability)

指的是只要事務(wù)成功結(jié)束,它對數(shù)據(jù)庫所做的更新就必須保存下來。即使發(fā)生系統(tǒng)崩潰,重新啟動數(shù)據(jù)庫系統(tǒng)后,數(shù)據(jù)庫還能恢復(fù)到事務(wù)成功結(jié)束時的狀態(tài)。

2.2、編程式事務(wù)

事務(wù)功能的相關(guān)操作全部通過自己編寫代碼來實(shí)現(xiàn):

Connection conn = ...;
    
try {
    
    // 開啟事務(wù):關(guān)閉事務(wù)的自動提交
    conn.setAutoCommit(false);
    
    // 核心操作
    
    // 提交事務(wù)
    conn.commit();
    
}catch(Exception e){
    
    // 回滾事務(wù)
    conn.rollBack();
    
}finally{
    
    // 釋放數(shù)據(jù)庫連接
    conn.close();
    
}

編程式的實(shí)現(xiàn)方式存在缺陷:

  • 細(xì)節(jié)沒有被屏蔽:具體操作過程中,所有細(xì)節(jié)都需要程序員自己來完成,比較繁瑣。
  • 代碼復(fù)用性不高:如果沒有有效抽取出來,每次實(shí)現(xiàn)功能都需要自己編寫代碼,代碼就沒有得到復(fù)用。
2.3、聲明式事務(wù)

既然事務(wù)控制的代碼有規(guī)律可循,代碼的結(jié)構(gòu)基本是確定的,所以框架就可以將固定模式的代碼抽取出來,進(jìn)行相關(guān)的封裝。

封裝起來后,我們只需要在配置文件中進(jìn)行簡單的配置即可完成操作。

  • 好處1:提高開發(fā)效率
  • 好處2:消除了冗余的代碼
  • 好處3:框架會綜合考慮相關(guān)領(lǐng)域中在實(shí)際開發(fā)環(huán)境下有可能遇到的各種問題,進(jìn)行了健壯性、性能等各個方面的優(yōu)化

所以,我們可以總結(jié)下面兩個概念:

  • 編程式自己寫代碼實(shí)現(xiàn)功能
  • 聲明式:通過配置框架實(shí)現(xiàn)功能

3、基于注解的聲明式事務(wù)

3.1、準(zhǔn)備工作

①添加配置

在beans.xml添加配置

<!--掃描組件-->
<context:component-scan base-package="com.atguigu.spring6"></context:component-scan>

②創(chuàng)建表

CREATE TABLE `t_book` (
  `book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `book_name` varchar(20) DEFAULT NULL COMMENT '圖書名稱',
  `price` int(11) DEFAULT NULL COMMENT '價(jià)格',
  `stock` int(10) unsigned DEFAULT NULL COMMENT '庫存(無符號)',
  PRIMARY KEY (`book_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert  into `t_book`(`book_id`,`book_name`,`price`,`stock`) values (1,'斗破蒼穹',80,100),(2,'斗羅大陸',50,100);
CREATE TABLE `t_user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `username` varchar(20) DEFAULT NULL COMMENT '用戶名',
  `balance` int(10) unsigned DEFAULT NULL COMMENT '余額(無符號)',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
insert  into `t_user`(`user_id`,`username`,`balance`) values (1,'admin',50);

③創(chuàng)建組件

創(chuàng)建BookController:

package com.atguigu.spring6.controller;

@Controller
public class BookController {

    @Autowired
    private BookService bookService;

    public void buyBook(Integer bookId, Integer userId){
        bookService.buyBook(bookId, userId);
    }
}

創(chuàng)建接口BookService:

package com.atguigu.spring6.service;
public interface BookService {
    void buyBook(Integer bookId, Integer userId);
}

創(chuàng)建實(shí)現(xiàn)類BookServiceImpl:

package com.atguigu.spring6.service.impl;
@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookDao bookDao;

    @Override
    public void buyBook(Integer bookId, Integer userId) {
        //查詢圖書的價(jià)格
        Integer price = bookDao.getPriceByBookId(bookId);
        //更新圖書的庫存
        bookDao.updateStock(bookId);
        //更新用戶的余額
        bookDao.updateBalance(userId, price);
    }
}

創(chuàng)建接口BookDao:

package com.atguigu.spring6.dao;
public interface BookDao {
    Integer getPriceByBookId(Integer bookId);

    void updateStock(Integer bookId);

    void updateBalance(Integer userId, Integer price);
}

創(chuàng)建實(shí)現(xiàn)類BookDaoImpl:

package com.atguigu.spring6.dao.impl;
@Repository
public class BookDaoImpl implements BookDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Integer getPriceByBookId(Integer bookId) {
        String sql = "select price from t_book where book_id = ?";
        return jdbcTemplate.queryForObject(sql, Integer.class, bookId);
    }

    @Override
    public void updateStock(Integer bookId) {
        String sql = "update t_book set stock = stock - 1 where book_id = ?";
        jdbcTemplate.update(sql, bookId);
    }

    @Override
    public void updateBalance(Integer userId, Integer price) {
        String sql = "update t_user set balance = balance - ? where user_id = ?";
        jdbcTemplate.update(sql, price, userId);
    }
}
3.2、測試無事務(wù)情況

①創(chuàng)建測試類

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

@SpringJUnitConfig(locations = "classpath:beans.xml")
public class TxByAnnotationTest {

    @Autowired
    private BookController bookController;

    @Test
    public void testBuyBook(){
        bookController.buyBook(1, 1);
    }

}

②模擬場景

用戶購買圖書,先查詢圖書的價(jià)格,再更新圖書的庫存和用戶的余額

假設(shè)用戶id為1的用戶,購買id為1的圖書

用戶余額為50,而圖書價(jià)格為80

購買圖書之后,用戶的余額為-30,數(shù)據(jù)庫中余額字段設(shè)置了無符號,因此無法將-30插入到余額字段

此時執(zhí)行sql語句會拋出SQLException

③觀察結(jié)果

因?yàn)闆]有添加事務(wù),圖書的庫存更新了,但是用戶的余額沒有更新

顯然這樣的結(jié)果是錯誤的,購買圖書是一個完整的功能,更新庫存和更新余額要么都成功要么都失敗

3.3、加入事務(wù)
①添加事務(wù)配置

在spring配置文件中引入tx命名空間

<?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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="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.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

在Spring的配置文件中添加配置:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

<!--
    開啟事務(wù)的注解驅(qū)動
    通過注解@Transactional所標(biāo)識的方法或標(biāo)識的類中所有的方法,都會被事務(wù)管理器管理事務(wù)
-->
<!-- transaction-manager屬性的默認(rèn)值是transactionManager,如果事務(wù)管理器bean的id正好就是這個默認(rèn)值,則可以省略這個屬性 -->
<tx:annotation-driven transaction-manager="transactionManager" />
②添加事務(wù)注解

因?yàn)閟ervice層表示業(yè)務(wù)邏輯層,一個方法表示一個完成的功能,因此處理事務(wù)一般在service層處理

在BookServiceImpl的buybook()添加注解@Transactional

③觀察結(jié)果

由于使用了Spring的聲明式事務(wù),更新庫存和更新余額都沒有執(zhí)行

3.4、@Transactional注解標(biāo)識的位置

@Transactional標(biāo)識在方法上,則只會影響該方法

@Transactional標(biāo)識的類上,則會影響類中所有的方法

3.5、事務(wù)屬性:只讀

①介紹

對一個查詢操作來說,如果我們把它設(shè)置成只讀,就能夠明確告訴數(shù)據(jù)庫,這個操作不涉及寫操作。這樣數(shù)據(jù)庫就能夠針對查詢操作來進(jìn)行優(yōu)化。

②使用方式

@Transactional(readOnly = true)
public void buyBook(Integer bookId, Integer userId) {
    //查詢圖書的價(jià)格
    Integer price = bookDao.getPriceByBookId(bookId);
    //更新圖書的庫存
    bookDao.updateStock(bookId);
    //更新用戶的余額
    bookDao.updateBalance(userId, price);
    //System.out.println(1/0);
}

③注意

對增刪改操作設(shè)置只讀會拋出下面異常:

Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

3.6、事務(wù)屬性:超時

①介紹

事務(wù)在執(zhí)行過程中,有可能因?yàn)橛龅侥承﹩栴},導(dǎo)致程序卡住,從而長時間占用數(shù)據(jù)庫資源。而長時間占用資源,大概率是因?yàn)槌绦蜻\(yùn)行出現(xiàn)了問題(可能是Java程序或MySQL數(shù)據(jù)庫或網(wǎng)絡(luò)連接等等)。此時這個很可能出問題的程序應(yīng)該被回滾,撤銷它已做的操作,事務(wù)結(jié)束,把資源讓出來,讓其他正常程序可以執(zhí)行。

概括來說就是一句話:超時回滾,釋放資源。

②使用方式

//超時時間單位秒
@Transactional(timeout = 3)
public void buyBook(Integer bookId, Integer userId) {
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    //查詢圖書的價(jià)格
    Integer price = bookDao.getPriceByBookId(bookId);
    //更新圖書的庫存
    bookDao.updateStock(bookId);
    //更新用戶的余額
    bookDao.updateBalance(userId, price);
    //System.out.println(1/0);
}

③觀察結(jié)果

執(zhí)行過程中拋出異常:

org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Fri Jun 04 16:25:39 CST 2022

3.7、事務(wù)屬性:回滾策略

①介紹

聲明式事務(wù)默認(rèn)只針對運(yùn)行時異?;貪L,編譯時異常不回滾。

可以通過@Transactional中相關(guān)屬性設(shè)置回滾策略

  • rollbackFor屬性:需要設(shè)置一個Class類型的對象

  • rollbackForClassName屬性:需要設(shè)置一個字符串類型的全類名

  • noRollbackFor屬性:需要設(shè)置一個Class類型的對象

  • rollbackFor屬性:需要設(shè)置一個字符串類型的全類名

②使用方式

@Transactional(noRollbackFor = ArithmeticException.class)
//@Transactional(noRollbackForClassName = "java.lang.ArithmeticException")
public void buyBook(Integer bookId, Integer userId) {
    //查詢圖書的價(jià)格
    Integer price = bookDao.getPriceByBookId(bookId);
    //更新圖書的庫存
    bookDao.updateStock(bookId);
    //更新用戶的余額
    bookDao.updateBalance(userId, price);
    System.out.println(1/0);
}

③觀察結(jié)果

雖然購買圖書功能中出現(xiàn)了數(shù)學(xué)運(yùn)算異常(ArithmeticException),但是我們設(shè)置的回滾策略是,當(dāng)出現(xiàn)ArithmeticException不發(fā)生回滾,因此購買圖書的操作正常執(zhí)行

3.8、事務(wù)屬性:隔離級別

①介紹

數(shù)據(jù)庫系統(tǒng)必須具有隔離并發(fā)運(yùn)行各個事務(wù)的能力,使它們不會相互影響,避免各種并發(fā)問題。一個事務(wù)與其他事務(wù)隔離的程度稱為隔離級別。SQL標(biāo)準(zhǔn)中規(guī)定了多種事務(wù)隔離級別,不同隔離級別對應(yīng)不同的干擾程度,隔離級別越高,數(shù)據(jù)一致性就越好,但并發(fā)性越弱。

隔離級別一共有四種:

  • 讀未提交:READ UNCOMMITTED

    允許Transaction01讀取Transaction02未提交的修改。

  • 讀已提交:READ COMMITTED、

    要求Transaction01只能讀取Transaction02已提交的修改。

  • 可重復(fù)讀:REPEATABLE READ

    確保Transaction01可以多次從一個字段中讀取到相同的值,即Transaction01執(zhí)行期間禁止其它事務(wù)對這個字段進(jìn)行更新。

  • 串行化:SERIALIZABLE

    確保Transaction01可以多次從一個表中讀取到相同的行,在Transaction01執(zhí)行期間,禁止其它事務(wù)對這個表進(jìn)行添加、更新、刪除操作??梢员苊馊魏尾l(fā)問題,但性能十分低下。

各個隔離級別解決并發(fā)問題的能力見下表:

隔離級別 臟讀 不可重復(fù)讀 幻讀
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

各種數(shù)據(jù)庫產(chǎn)品對事務(wù)隔離級別的支持程度:

隔離級別 Oracle MySQL
READ UNCOMMITTED ×
READ COMMITTED √(默認(rèn))
REPEATABLE READ × √(默認(rèn))
SERIALIZABLE

②使用方式

@Transactional(isolation = Isolation.DEFAULT)//使用數(shù)據(jù)庫默認(rèn)的隔離級別
@Transactional(isolation = Isolation.READ_UNCOMMITTED)//讀未提交
@Transactional(isolation = Isolation.READ_COMMITTED)//讀已提交
@Transactional(isolation = Isolation.REPEATABLE_READ)//可重復(fù)讀
@Transactional(isolation = Isolation.SERIALIZABLE)//串行化
3.9、事務(wù)屬性:傳播行為

①介紹

什么是事務(wù)的傳播行為?

在service類中有a()方法和b()方法,a()方法上有事務(wù),b()方法上也有事務(wù),當(dāng)a()方法執(zhí)行過程中調(diào)用了b()方法,事務(wù)是如何傳遞的?合并到一個事務(wù)里?還是開啟一個新的事務(wù)?這就是事務(wù)傳播行為。

一共有七種傳播行為:

  • REQUIRED:支持當(dāng)前事務(wù),如果不存在就新建一個(默認(rèn))【沒有就新建,有就加入】
  • SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行**【有就加入,沒有就不管了】**
  • MANDATORY:必須運(yùn)行在一個事務(wù)中,如果當(dāng)前沒有事務(wù)正在發(fā)生,將拋出一個異常**【有就加入,沒有就拋異?!?*
  • REQUIRES_NEW:開啟一個新的事務(wù),如果一個事務(wù)已經(jīng)存在,則將這個存在的事務(wù)掛起**【不管有沒有,直接開啟一個新事務(wù),開啟的新事務(wù)和之前的事務(wù)不存在嵌套關(guān)系,之前事務(wù)被掛起】**
  • NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,掛起當(dāng)前事務(wù)**【不支持事務(wù),存在就掛起】**
  • NEVER:以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,拋出異常**【不支持事務(wù),存在就拋異?!?*
  • NESTED:如果當(dāng)前正有一個事務(wù)在進(jìn)行中,則該方法應(yīng)當(dāng)運(yùn)行在一個嵌套式事務(wù)中。被嵌套的事務(wù)可以獨(dú)立于外層事務(wù)進(jìn)行提交或回滾。如果外層事務(wù)不存在,行為就像REQUIRED一樣。【有事務(wù)的話,就在這個事務(wù)里再嵌套一個完全獨(dú)立的事務(wù),嵌套的事務(wù)可以獨(dú)立的提交和回滾。沒有事務(wù)就和REQUIRED一樣。】

②測試

創(chuàng)建接口CheckoutService:

package com.atguigu.spring6.service;

public interface CheckoutService {
    void checkout(Integer[] bookIds, Integer userId);
}

創(chuàng)建實(shí)現(xiàn)類CheckoutServiceImpl:

package com.atguigu.spring6.service.impl;

@Service
public class CheckoutServiceImpl implements CheckoutService {

    @Autowired
    private BookService bookService;

    @Override
    @Transactional
    //一次購買多本圖書
    public void checkout(Integer[] bookIds, Integer userId) {
        for (Integer bookId : bookIds) {
            bookService.buyBook(bookId, userId);
        }
    }
}

在BookController中添加方法:

@Autowired
private CheckoutService checkoutService;

public void checkout(Integer[] bookIds, Integer userId){
    checkoutService.checkout(bookIds, userId);
}

在數(shù)據(jù)庫中將用戶的余額修改為100元

③觀察結(jié)果

可以通過@Transactional中的propagation屬性設(shè)置事務(wù)傳播行為

修改BookServiceImpl中buyBook()上,注解@Transactional的propagation屬性

@Transactional(propagation = Propagation.REQUIRED),默認(rèn)情況,表示如果當(dāng)前線程上有已經(jīng)開啟的事務(wù)可用,那么就在這個事務(wù)中運(yùn)行。經(jīng)過觀察,購買圖書的方法buyBook()在checkout()中被調(diào)用,checkout()上有事務(wù)注解,因此在此事務(wù)中執(zhí)行。所購買的兩本圖書的價(jià)格為80和50,而用戶的余額為100,因此在購買第二本圖書時余額不足失敗,導(dǎo)致整個checkout()回滾,即只要有一本書買不了,就都買不了

@Transactional(propagation = Propagation.REQUIRES_NEW),表示不管當(dāng)前線程上是否有已經(jīng)開啟的事務(wù),都要開啟新事務(wù)。同樣的場景,每次購買圖書都是在buyBook()的事務(wù)中執(zhí)行,因此第一本圖書購買成功,事務(wù)結(jié)束,第二本圖書購買失敗,只在第二次的buyBook()中回滾,購買第一本圖書不受影響,即能買幾本就買幾本。

3.10、全注解配置事務(wù)

①添加配置類

package com.atguigu.spring6.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;

@Configuration
@ComponentScan("com.atguigu.spring6")
@EnableTransactionManagement
public class SpringConfig {

    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

②測試

import com.atguigu.spring6.config.SpringConfig;
import com.atguigu.spring6.controller.BookController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

public class TxByAllAnnotationTest {

    @Test
    public void testTxAllAnnotation(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookController accountService = applicationContext.getBean("bookController", BookController.class);
        accountService.buyBook(1, 1);
    }
}

4、基于XML的聲明式事務(wù)

4.1、場景模擬

參考基于注解的聲明式事務(wù)

4.2、修改Spring配置文件

將Spring配置文件中去掉tx:annotation-driven 標(biāo)簽,并添加配置:

<aop:config>
    <!-- 配置事務(wù)通知和切入點(diǎn)表達(dá)式 -->
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.atguigu.spring.tx.xml.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- tx:advice標(biāo)簽:配置事務(wù)通知 -->
<!-- id屬性:給事務(wù)通知標(biāo)簽設(shè)置唯一標(biāo)識,便于引用 -->
<!-- transaction-manager屬性:關(guān)聯(lián)事務(wù)管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- tx:method標(biāo)簽:配置具體的事務(wù)方法 -->
        <!-- name屬性:指定方法名,可以使用星號代表多個字符 -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="query*" read-only="true"/>
        <tx:method name="find*" read-only="true"/>
    
        <!-- read-only屬性:設(shè)置只讀屬性 -->
        <!-- rollback-for屬性:設(shè)置回滾的異常 -->
        <!-- no-rollback-for屬性:設(shè)置不回滾的異常 -->
        <!-- isolation屬性:設(shè)置事務(wù)的隔離級別 -->
        <!-- timeout屬性:設(shè)置事務(wù)的超時屬性 -->
        <!-- propagation屬性:設(shè)置事務(wù)的傳播行為 -->
        <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
    </tx:attributes>
</tx:advice>

注意:基于xml實(shí)現(xiàn)的聲明式事務(wù),必須引入aspectJ的依賴文章來源地址http://www.zghlxwxcb.cn/news/detail-713740.html

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>6.0.2</version>
</dependency>

到了這里,關(guān)于spring6-事務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 2、Spring6 入門

    2、Spring6 入門

    JDK:Java17+ (Spring6要求JDK最低版本是Java17) Maven:3.6+ Spring:6.0.2 點(diǎn)擊“Create” ? ? 點(diǎn)擊 Create 完成. ? 查看依賴: ? 在resources目錄創(chuàng)建一個 Spring 配置文件 bean.xml(配置文件名稱可隨意命名,如:springs.xml) ?以前我們創(chuàng)建對象的方式是通過 的方式,但是現(xiàn)在我們可以把創(chuàng)建

    2024年02月10日
    瀏覽(21)
  • Spring6 初始

    Spring6 初始

    @ 目錄 Spring6 初始 每博一文案: 1. 初始 Spring6 1.1 OCP開閉原則 1.2 依賴倒置原則DIP 1.3 控制反轉(zhuǎn)IoC 2. Spring 初始 2.1 Spring特點(diǎn) 2.2 Spring6 的下載: 2.3 Spring的jar文件 3. 第一個Spring 程序的編寫 4. 第一個Spring程序詳細(xì)剖析 4.1 bean標(biāo)簽的id屬性可以重復(fù)嗎? 4.2 底層是怎么創(chuàng)建對象的,是

    2024年02月17日
    瀏覽(21)
  • spring6詳細(xì)講解

    spring6詳細(xì)講解

    1.1、Spring是什么? Spring 是一款主流的 Java EE 輕量級開源框架 ,Spring 由“Spring 之父”Rod Johnson 提出并創(chuàng)立,其目的是用于簡化 Java 企業(yè)級應(yīng)用的開發(fā)難度和開發(fā)周期。Spring的用途不僅限于服務(wù)器端的開發(fā)。從簡單性、可測試性和松耦合的角度而言,任何Java應(yīng)用都可以從Spr

    2024年02月10日
    瀏覽(27)
  • spring6概述

    spring6概述

    1.1、Spring是什么? Spring 是一款主流的 Java EE 輕量級開源框架 ,Spring 由“Spring 之父”Rod Johnson 提出并創(chuàng)立,其目的是用于簡化 Java 企業(yè)級應(yīng)用的開發(fā)難度和開發(fā)周期。Spring的用途不僅限于服務(wù)器端的開發(fā)。從簡單性、可測試性和松耦合的角度而言,任何Java應(yīng)用都可以從Spr

    2024年02月08日
    瀏覽(51)
  • Spring6-01

    Spring6-01

    什么是開閉原則? 在軟件開發(fā)過程中應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉。 也就是說如果在進(jìn)行功能擴(kuò)展的時候,添加額外的類是沒有問題的,但因?yàn)楣δ軘U(kuò)展而修改之前運(yùn)行正常的程序,這是不被允許的。因?yàn)橐坏┬薷牧酥斑\(yùn)行正常的程序,就會導(dǎo)致項(xiàng)目整體要進(jìn)行整體的全

    2024年02月08日
    瀏覽(19)
  • 【Spring6】| Spring IoC注解式開發(fā)

    【Spring6】| Spring IoC注解式開發(fā)

    目錄 一:Spring IoC注解式開發(fā) 1.?回顧注解 2.?聲明Bean的四個注解 3.?Spring注解的使用 4.?選擇性實(shí)例化Bean 5.?負(fù)責(zé)注入的注解(重點(diǎn)) 5.1 @Value 5.2?@Autowired與@Qualifier 5.3?@Resource 6.?全注解式開發(fā) 注解的存在主要是為了簡化XML的配置 ,Spring6倡導(dǎo)全注解開發(fā)。 我們來回顧一下:

    2023年04月12日
    瀏覽(25)
  • 【Spring6】| 簡述Spring中的八大模式

    【Spring6】| 簡述Spring中的八大模式

    Spring中的八大模式,有很多我們前面已經(jīng)講過了,這里只需要大概有個印象,后期會出一個專門對23種設(shè)計(jì)模式的詳解! 1.?簡單工廠模式 BeanFactory的getBean()方法,通過唯一標(biāo)識來獲取Bean對象。是典型的簡單工廠模式(靜態(tài)工廠模式);主要包括三部分:抽象產(chǎn)品角色、具體

    2023年04月21日
    瀏覽(20)
  • Java后端07(Spring)

    ?涉及的設(shè)計(jì)模式:單例模式,簡單工廠模式,代理模式,觀察者模式,反射,注解。。。。。 ?在傳統(tǒng)模式下,對象的創(chuàng)建和賦值,都是由開發(fā)者自己手動完成,事實(shí)情況下,開發(fā)者只關(guān)心如何獲取賦值好的對象,但是并不希望自己手動進(jìn)行創(chuàng)建對象和賦值的事情(sprin

    2024年02月13日
    瀏覽(26)
  • Spring6源碼編譯、安裝

    Spring6源碼編譯、安裝

    名稱 版本 jdk 17 gradle 8.1.1 spring源碼版本 6.0.9 下載并解壓 配置環(huán)境變量 驗(yàn)證 下載并解壓 配置環(huán)境變量 驗(yàn)證 配置鏡像倉庫 spring在Github官網(wǎng)上有詳細(xì)的說明文檔,可以參考,但按照步驟做輝有些報(bào)錯??,還是按照自己總結(jié)的步驟來吧。 github源碼地址 國內(nèi)gitcode鏡像 官方構(gòu)建

    2024年02月08日
    瀏覽(17)
  • Spring6.0 源碼部署

    Spring6.0 源碼部署

    Git JDK17 Gradle(版本號需要和Spring源碼中的版本一致) 官網(wǎng)地址

    2024年02月16日
    瀏覽(58)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包