天天看點

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

 目錄

一、知識點

1.1 聲明式事務操作

1.2 相關依賴

二、例1:普通例子

2.1 建立資料庫和表

2.2 目錄結構

2.3 實作代碼

2.4 運作結果

三、例2:在例1的基礎上添加事務@Transactional 

3.1 模式事務

3.2 開啟事務

3.3 配置事務管理器來控制事務

什麼是事務,簡單來說,就是要幾個sql綁在一起,要麼所有執行成功,要麼所有執行失敗,不能出現隻執行部分的情況。

經典的就是銀行轉帳,A向B轉帳,最少需要執行2步,2個sql

步驟1:查詢A餘額是否足夠,然後在A-轉賬金額

步驟2:B賬号添加A轉賬數

你不能隻執行一個吧?!這是絕對不能出現隻執行成功一個的,如果隻有一部分執行成功,那麼就要全部復原,并提示失敗。

一、知識點

1.1 聲明式事務操作

1.給方法上方 @Transactional 表示目前方法是一個事務方法

[email protected] 開啟基于注解的事務管理功能

    @EnableXXX  不開啟的話,事務是不會被執行的

3.配置事務管理器來控制事務

      @Bean

      public PlatformTransactionManager transactionManager() throws Exception{}

1.2 相關依賴

c3p0、mchange-commons-java、mysql-connector-java、spring-jdbc

pom.xml要有如下配置:我目前的spring版本為5.2.3,涉及有spring的版本要一緻,其它的版本可以去maven官網倉庫查

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

        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>mchange-commons-java</artifactId>
            <version>0.2.20</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
           

c3p0:主要是讀取外部配置檔案,一般資料庫配置檔案放在外部,我這裡使用yml方式

mchange-commons-java:c3p0資料庫連接配接池的輔助包

mysql-connector-java:mysql的jdbc驅動包,是java連接配接mysql資料庫使用的,我這裡隻是配置檔案,并沒用到mysql資料庫

spring-jdbc:spring操作jdbc操作資料庫用的,如mysql資料庫

二、例1:普通例子

2.1 建立資料庫和表

我在hua資料庫如下:

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

表如下:

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

插入資料

INSERT INTO tb1_user (username,age) VALUES ('admin',18)
           

2.2 目錄結構

2.3 實作代碼

com.hualinux.tx.UserDao.java

package com.hualinux.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insert(){
        String sql = "INSERT INTO tb1_user (username,age) VALUES (?,?)";
        String username  = UUID.randomUUID().toString().substring(0,5);
        jdbcTemplate.update(sql,username,19);
    }
}
           

com.hualinux.tx.UserService.java

package com.hualinux.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    
    public void insertUser(){
        userDao.insert();
        System.out.println("插入完成...");
    }
}
           

resources-->db.yml

我是直接使用《hualinux spring 4.16:@Profile 切換環境》中的資料庫配置檔案db.yml,隻是修改了使用者名和密碼

user: hua
pwd: hua123
driverClass: com.mysql.cj.jdbc.Driver
jdbcUrlTest: jdbc:mysql://127.0.0.1:3306/hua_test?serverTimezone=GMT%2B8
jdbcUrlDev: jdbc:mysql://127.0.0.1:3306/hua_dev?serverTimezone=GMT%2B8"
jdbcUrlProd: jdbc:mysql://127.0.0.1:3306/hua?serverTimezone=GMT%2B8
           
注:下面值不能加雙引号或引号,如果加了會連引号一起擷取的
#下面寫法是錯誤的
driverClass: "com.mysql.cj.jdbc.Driver"
jdbcUrlTest: "jdbc:mysql://127.0.0.1:3306/hua_test?serverTimezone=GMT%2B8"
jdbcUrlDev: "jdbc:mysql://127.0.0.1:3306/hua_dev?serverTimezone=GMT%2B8"
jdbcUrlProd: "jdbc:mysql://127.0.0.1:3306/hua?serverTimezone=GMT%2B8"
           

 com.hualinux.tx.TxConf.java配置如下

package com.hualinux.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;


/*
* 聲明式事務:
*
* 環境搭建:
* 1.導入相關依賴:資料源、資料庫驅動c3p0、Springjdbc模拟
* 2.配置資料源:JdbcTemplate(Spring提供的簡化資料庫操作的工具)操作資料
* */
@PropertySource(value={"classpath:/db.yml"})
@ComponentScan("com.hualinux.tx")
@Configuration
public class TxConf {

    @Value("${user}")
    private String user;
    @Value("${pwd}")
    private String pwd;
    @Value("${driverClass}")
    private String driverClass;
    @Value("${jdbcUrlTest}")
    private String jdbcUrlTest;
    @Value("${jdbcUrlDev}")
    private String jdbcUrlDev;
    @Value("${jdbcUrlProd}")
    private String jdbcUrlProd;


    //資料源
    @Bean
    public DataSource dataSource() throws Exception{
        //主要是測試一下是否讀到db.yml檔案資料,及是否填寫正确
        System.out.println(user+"\n"+pwd+"\n"+jdbcUrlProd+"\n"+driverClass);
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setDriverClass(driverClass);
        //測試環境使用的資料庫
        dataSource.setJdbcUrl(jdbcUrlProd);
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception{
        //Spring對@Configuration類會特殊處理;給容器中加元件的方法,多次調用都隻是從容器找元件
        //下面dataSource(),是找元件并不是運作一次方法,因為這個類是配置類
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }


}
           

src-->test-->java-->IOCTest_Tx.java代碼

import com.hualinux.tx.TxConf;
import com.hualinux.tx.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

class IOCTest_Tx {
    AnnotationConfigApplicationContext ctx;

    @Test
    public void test01() {
        ctx = new AnnotationConfigApplicationContext(TxConf.class);
        UserService userService = ctx.getBean(UserService.class);

        userService.insertUser();
        ctx.close();
    }

}
           

2.4 運作結果

運作上面的IOCTest_Tx.java中的測試方法test01,如果資料庫打開能連接配接使用者名和密碼沒問題,最後會提示

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

檢視資料庫變化

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

三、例2:在例1的基礎上添加事務@Transactional 

3.1 模式事務

com.hualinux.tx.UserService.java類在最後添加一條語句模拟事務,如下:

package com.hualinux.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    @Transactional
    public void insertUser(){
        userDao.insert();
        System.out.println("插入完成...");
        //之前的是沒有事務的,模拟事務添加一條,要求不成功就復原
        int i=10/0;

    }
}
           

再運作IOCTest_TxTest.java中的test01方法,效果如下

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

抛異常了,檢視一下表沒有第3條資料插入,發現還是插入了

hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

 說明事務沒生效啊!!因為預設事務是關閉的,沒有開啟,需要添加一個開啟的注解。

@EnableLoadTimeWeaving 開啟基于注解的事務管理功能

@EnableXXX  不開啟的話,事務是不會被執行的
           

3.2 開啟事務

是以事務配置類得開啟一下,com.hualinux.tx.TxConf.java代碼,在類頂上添加多一個注解

@EnableLoadTimeWeaving
           

整個代碼如下:

package com.hualinux.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;


/*
 * 聲明式事務:
 *
 * 環境搭建:
 * 1.導入相關依賴:資料源、資料庫驅動c3p0、Springjdbc模拟
 * 2.配置資料源:JdbcTemplate(Spring提供的簡化資料庫操作的工具)操作資料
 * 3.給方法上歀 @Transactional 表示目前方法是一個事務方法
 * [email protected] 開啟基于注解的事務管理功能
 *     @EnableXXX  不開啟的話,事務是不會被執行的
 * */
@EnableLoadTimeWeaving
@PropertySource(value={"classpath:/db.yml"})
@ComponentScan("com.hualinux.tx")
@Configuration
public class TxConf {

    @Value("${user}")
    private String user;
    @Value("${pwd}")
    private String pwd;
    @Value("${driverClass}")
    private String driverClass;
    @Value("${jdbcUrlTest}")
    private String jdbcUrlTest;
    @Value("${jdbcUrlDev}")
    private String jdbcUrlDev;
    @Value("${jdbcUrlProd}")
    private String jdbcUrlProd;


    //資料源
    @Bean
    public DataSource dataSource() throws Exception{
        //主要是測試一下是否讀到db.yml檔案資料,及是否填寫正确
        System.out.println(user+"\n"+pwd+"\n"+jdbcUrlProd+"\n"+driverClass);
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setDriverClass(driverClass);
        //測試環境使用的資料庫
        dataSource.setJdbcUrl(jdbcUrlProd);
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception{
        //Spring對@Configuration類會特殊處理;給容器中加元件的方法,多次調用都隻是從容器找元件
        //下面dataSource(),是找元件并不是運作一次方法,因為這個類是配置類
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }


}
           

再運作IOCTest_TxTest.java中的test01方法,發現報如下錯誤:

Error creating bean with name 'loadTimeWeaver' defined in org.springframework.context.annotation.LoadTimeWeavingConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.instrument.classloading.LoadTimeWeaver]: Factory method 'loadTimeWeaver' threw exception; nested exception is java.lang.IllegalStateException: ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-instrument-{version}.jar
hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

再去看一下資料庫是否有變化,發現不有變化,是以完成了。

3.3 配置事務管理器來控制事務

com.hualinux.tx.TxConf.java代碼,添加多一段代碼

//注冊事務管理器在容器中
    @Bean
    public PlatformTransactionManager transactionManager() throws Exception{
        return  new DataSourceTransactionManager(dataSource());
    }
           

整個代碼如下: 

package com.hualinux.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;


/*
 * 聲明式事務:
 *
 * 環境搭建:
 * 1.導入相關依賴:資料源、資料庫驅動c3p0、Springjdbc模拟
 * 2.配置資料源:JdbcTemplate(Spring提供的簡化資料庫操作的工具)操作資料
 * 3.給方法上歀 @Transactional 表示目前方法是一個事務方法
 * [email protected] 開啟基于注解的事務管理功能
 *     @EnableXXX  不開啟的話,事務是不會被執行的
 * */
@EnableLoadTimeWeaving
@PropertySource(value={"classpath:/db.yml"})
@ComponentScan("com.hualinux.tx")
@Configuration
public class TxConf {

    @Value("${user}")
    private String user;
    @Value("${pwd}")
    private String pwd;
    @Value("${driverClass}")
    private String driverClass;
    @Value("${jdbcUrlTest}")
    private String jdbcUrlTest;
    @Value("${jdbcUrlDev}")
    private String jdbcUrlDev;
    @Value("${jdbcUrlProd}")
    private String jdbcUrlProd;


    //資料源
    @Bean
    public DataSource dataSource() throws Exception{
        //主要是測試一下是否讀到db.yml檔案資料,及是否填寫正确
        System.out.println(user+"\n"+pwd+"\n"+jdbcUrlProd+"\n"+driverClass);
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setDriverClass(driverClass);
        //測試環境使用的資料庫
        dataSource.setJdbcUrl(jdbcUrlProd);
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception{
        //Spring對@Configuration類會特殊處理;給容器中加元件的方法,多次調用都隻是從容器找元件
        //下面dataSource(),是找元件并不是運作一次方法,因為這個類是配置類
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }

    //注冊事務管理器在容器中
    @Bean
    public PlatformTransactionManager transactionManager() throws Exception{
        return  new DataSourceTransactionManager(dataSource());
    }

}
           
hualinux spring 4.18:@Transactional 聲明式事務一、知識點二、例1:普通例子三、例2:在例1的基礎上添加事務@Transactional 

繼續閱讀