1. 程式人生 > 其它 >【Spring5】資料庫事務操作

【Spring5】資料庫事務操作

Spring針對事務的操作

事務的概念:事務是資料庫最基本的單元,邏輯上的一組操作,要麼都成功,如果有一個操作失敗則都失敗。

事務的特性:ACID

原子性、一致性、隔離性、永續性

JavaEE環境三層結構

1.WEB檢視層

2.Service業務邏輯層

主要包含一些業務邏輯

3.資料訪問層

包含對資料庫操作的方法,不涉及業務的操作

(1)事務新增到JavaEE三層結構的Service業務邏輯層

(2)在Spring進行事務管理操作,有兩種方式:

①程式設計式事務管理:set autocommit = false

哪些操作會導致資料庫的自動提交?

1.DDL操作一旦執行,都會自動提交,set autocommit = false對DDL操作無效。

2.DML預設情況會自動提交,可以通過set autocommit = false的方式取消DML操作的自動提交。

DML(Data Manipulation Language)資料操縱語言:

適用範圍:對資料庫中的資料進行一些簡單操作,如insert,delete,update,select等.

DDL(Data Definition Language)資料定義語言:

適用範圍:對資料庫中的某些物件(例如,database,table)進行管理,如Create,Alter和Drop.

    @Test
    public void updateTest() {

        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            conn.setAutoCommit(false);

//            System.out.println(conn.getAutoCommit());

            String sql1 = "update user set balance = balance - 100 where uer=?";
            update(conn, sql1, "AA");

            System.out.println(1/0);

            String sql2 = "update user set balance = balance + 100 where uer=?";
            update(conn, sql2, "2B");

            System.out.println("轉賬成功");
            conn.commit();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if(conn!=null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


    }

宣告式事務管理

基於註解方式(使用)

1.建立事務管理器 DataSourceTractionManager,並注入資料來源(資料庫連線池)

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

2.在配置檔案中引入名稱空間tx

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

3.開啟事務註解

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

4.在Service中新增事務註解@Tranctional

在類上面新增此註解,則類中所有方法都新增到事務,若新增到方法上,則此方法新增到事務。

    @Transactional
    public void accountMoney(String id1, String id2, double money) {
        accountDao.reduceMoney(id1, money);

        System.out.println(1/0);

        accountDao.addMoney(id2, money);
    }

錢數不會發生變化

註解@Transactional的相關引數

1.propagation 事務傳播行為

事務的傳播行為,指的是多事務之間進行呼叫時,這個過程中的是如何管理的。

![](file://D:\資料\學習筆記\Java\Spring\2.png?msec=1649505122694)

事務的傳播行為由傳播屬性指定。Spring定義了7種傳播行為,重點記住前兩個。

傳播屬性 描述
REQURED 如果呼叫方法有事務在執行,當前方法就在這個事務中執行,否則,就啟動一個自己的新的事務,並在此事務中執行。(如上圖)
REQURED_NEW 當前方法必須啟動自己的事務,並在自己的事務中進行,如果呼叫方法中有事務在執行,則應該將其掛起
SUPPORTS
NOT_SUPPORTED
MANDATORY
NEVER
NESTED
@Transactional(propagation = Propagation.REQUIRED)

2.isolation 事務隔離級別

事務的隔離性,是指多事務之間操作不會受彼此影響,不考慮隔離性會產生很多問題:

①髒讀:一個事務讀取到了另一個未提交事務的資料(即兩個事務都沒有提交,事務可能回滾導致另一個事務讀到髒資料)

②不可重複讀:一個未提交事務讀取到另一提交事務修改資料

![](file://D:\資料\學習筆記\Java\Spring\3.png?msec=1649505122695)

未提交事務的事務兩次讀到的資料不一致,正常情況下是不能讀取資料的

髒讀是一個問題,但是不可重複讀是一種現象,是允許發生的

③幻讀:一個未提交事務讀到另一個提交事務新增的資料,兩次讀到的行數不一致

通過設定事務隔離級別,解決讀問題

髒讀 不可重複讀 幻讀
Read Uncommitted
(讀未提交)
Read Committed
(讀已提交)
Repeatable Read
(可重複讀)
Serializable
(可序列化)
@Transactional(isolation = Isolation.SERIALIZABLE)

MySQL預設級別為REPEATABLE READ可重複讀

3.timeout 超時時間

事務需要在一定時間內進行提交,超過這個時間就會回滾

預設值為-1,表示不超時,值以s為單位

4.readOnly 是否只讀

讀:查詢操作

寫:新增修改刪除操作

5.rollbackFor 事務回滾

設定出現哪些異常進行事務的回滾

6.noRollbackFor 事務不回滾

設定出現哪些異常不進行事務的回滾

只需設定為異常的Class即可

基於XML配置檔案方式

(4)在Spring進行宣告式事務管理,底層使用AOP原理

(5)Spring事務管理API

完全註解開發
@Configuration //配置類
@ComponentScan(basePackages = "com.hikaru") //掃描元件
@EnableTransactionManagement //開啟事務
public class TxConfig {
    @Bean
    public DruidDataSource getDataSource() throws IOException {
        DruidDataSource druidDataSource = new DruidDataSource();

        InputStream is = TxConfig.class.getClassLoader().getResourceAsStream("JDBC.properties");
        Properties properties = new Properties();
        properties.load(is);

        String driverClassName = properties.getProperty("driverClassName");
        String url = properties.getProperty("url");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");

        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);

        return druidDataSource;
    }

    @Bean
    public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager() ;
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);

        return jdbcTemplate;
    }

    @Test
    public void test() throws IOException, SQLException {
        DruidDataSource druidDataSource = getDataSource();
        System.out.println(druidDataSource.getConnection());
    }
}

其中@Bean作用是將方法返回值注入IOC容器

配置類方法中的形參均在IOC容器中找到

測試

    @Test
    public void test() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(TxConfig.class);
        AccountService accountService = context.getBean("accountService", AccountService.class);
        accountService.accountMoney("1001", "1002", 500);
    }