天天看點

五、事務操作

五、事務操作

  • ​​五、事務操作​​
  • ​​事務概念​​
  • ​​1、什麼是事務​​
  • ​​(1)事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果有一個失敗所有操作都失敗​​
  • ​​(2)典型場景:銀行轉賬​​
  • ​​2、事務特性(ACID)​​
  • ​​(1)原子性​​
  • ​​(2)一緻性​​
  • ​​(3)隔離性​​
  • ​​(4)持久性​​
  • ​​事務操作(搭建事務操作環境)​​
  • ​​1、建立資料庫表,添加記錄​​
  • ​​2、建立service,搭建dao,完成對象建立和注入關系​​
  • ​​(1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource​​
  • ​​建立子產品spring5_txdemo1/service/UserService​​
  • ​​dao/UseDao​​
  • ​​dao/UseDaoImpl​​
  • ​​3、在dao建立兩個方法,多錢和少錢的方法,在service建立方法(轉賬的方法)​​
  • ​​UserDaoImpl​​
  • ​​UserService​​
  • ​​test/testTx​​
  • ​​4、上面代碼,如果正常執行沒有問題的,但是如果代碼執行過程中出現異常,有問題​​
  • ​​(1)上面問題如何解決呢?​​
  • ​​(2)事務操作過程​​
  • ​​事務操作(Spring事務管理介紹)​​
  • ​​事務操作(注解聲明式事務管理)​​
  • ​​1、在spring配置檔案配置事務管理器​​
  • ​​bean1.xml​​
  • ​​2、在spring配置檔案,開啟事務注解​​
  • ​​(1)在spring配置檔案引入名稱空間tx​​
  • ​​(2)開啟事務注解​​
  • ​​3、在service類上面(或者service類裡面的方法上面)添加事務注解​​
  • ​​執行testAccount​​
  • ​​事務操作(聲明式事務管理參數配置)​​
  • ​​事務操作(XML聲明式事務管理)​​
  • ​​1、在spring配置檔案中進行配置​​
  • ​​第一步 配置事務管理器​​
  • ​​第二步 配置通知​​
  • ​​第三步 配置切入點和切面​​
  • ​​src/建立bean2.xml​​
  • ​​UserService​​
  • ​​testTX​​
  • ​​事務操作(完全注解聲明式事務管理)​​
  • ​​1、建立配置類,使用配置類替代xml配置檔案​​
  • ​​spring5/建立config包/建立TxConfig​​
  • ​​UserService​​
  • ​​testTX​​

說明

五、事務操作

事務概念

1、什麼是事務

(1)事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果有一個失敗所有操作都失敗

(2)典型場景:銀行轉賬

  • lucy 轉賬100元給 mary
  • lucy少100,mary多100

2、事務特性(ACID)

(1)原子性

(2)一緻性

(3)隔離性

(4)持久性

事務操作(搭建事務操作環境)

五、事務操作

1、建立資料庫表,添加記錄

五、事務操作
五、事務操作

2、建立service,搭建dao,完成對象建立和注入關系

(1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource

建立子產品spring5_txdemo1/service/UserService
package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;
}      
dao/UseDao
package com.atguigu.spring5.dao;


public interface UserDao {

}      
dao/UseDaoImpl
package com.atguigu.spring5.dao;

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

@Repository
public class UserDaoImpl implements UserDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
}      

3、在dao建立兩個方法,多錢和少錢的方法,在service建立方法(轉賬的方法)

UserDaoImpl
//lucy轉賬100給mary
    //少錢
    @Override
    public void reduceMoney() {
        String sql="update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }

    //多錢
    @Override
    public void addMoney() {
        String sql="update t_account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"mary");
    }      
UserService
//轉賬的方法
    public void accountMoney(){
        //lucy少100
        userDao.reduceMoney();
        //mary多100
        userDao.addMoney();
    }      
test/testTx
package com.atguigu.spring5.test;

import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testTX {
    @Test
    public void testAccount(){
        ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }
}      

4、上面代碼,如果正常執行沒有問題的,但是如果代碼執行過程中出現異常,有問題

五、事務操作

(1)上面問題如何解決呢?

  • 使用事務進行解決

(2)事務操作過程

五、事務操作

事務操作(Spring事務管理介紹)

1、事務添加到JavaEE三層結構裡面Service層(業務邏輯層)

2、在Spring進行事務管理操作

(1)有兩種操作:程式設計式事務管理和聲明式事務管理(使用)

3、聲明式事務管理

(1)基于注解方式

(2)基于xml配置檔案方式

4、在Spring進行聲明式事務管理,底層使用AOP原理

5、Spring事務管理API

(1)提供一個接口,代表事務管理器,這個接口針對不同的架構提供不同的實作類

五、事務操作

事務操作(注解聲明式事務管理)

1、在spring配置檔案配置事務管理器

bean1.xml
<!--建立事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入資料源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>      

2、在spring配置檔案,開啟事務注解

(1)在spring配置檔案引入名稱空間tx

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

(2)開啟事務注解

<!--開啟事務注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>      

3、在service類上面(或者service類裡面的方法上面)添加事務注解

(1)@Transactional,這個注解添加到類上面,也可以添加到方法上面

(2)如果把這個注解添加到類上面,這個類裡面所有方法都添加事務

(3)如果把這個注解添加到方法上面,為這個方法添加事務

@Service
@Transactional
public class UserService {      
執行testAccount

資料沒變

事務操作(聲明式事務管理參數配置)

1、在service類上面添加注解@Transactional,在這個注解裡面可以配置事務相關的參數

五、事務操作

2、propagation:事務傳播行為

(1)多事務方法之間進行調用,這個過程中事務是如何進行管理的

五、事務操作
五、事務操作
五、事務操作

3、isolation:事務隔離級别

(1)事務有特性,稱作隔離性,多事務操作之間不會影響。不考慮隔離性産生很多問題

(2)有三個讀問題:髒讀、不可重複讀、虛(幻)讀

(3)髒讀:一個為送出事務讀取到另一個為送出事務的資料

五、事務操作

(4)不可重複讀:一個未送出事務讀取到另一送出事務修改資料

五、事務操作

(5)虛讀:一個未送出事務讀取到另一送出事務添加資料

(6)通過設定事務隔離級别,解決讀問題

五、事務操作

事務操作(XML聲明式事務管理)

1、在spring配置檔案中進行配置

第一步 配置事務管理器

第二步 配置通知

第三步 配置切入點和切面

src/建立bean2.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:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

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

    <!-- 資料庫連接配接池 -->
    <!-- 配置連接配接池 -->
    <!-- DruidDataSource dataSource = new DruidDataSource(); -->

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close"     >
        <property name="url" value="jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    </bean>

    <!-- JdbcTemplate對象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--1 建立事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入資料源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--2 配置通知    -->
    <tx:advice id="txadvice">
        <!-- 配置事務參數 -->
        <tx:attributes>
            <!-- 指定那種規則的方法上面添加事務 -->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
<!--            <tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>

    <!--3 配置切入點和切面-->
    <aop:config>
        <!-- 配置切入點       -->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!-- 配置切面       -->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
</beans>      
UserService
package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
//@Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;

    //轉賬的方法
    public void accountMoney(){
//        try {
            //第一步   開啟事務

            //第二部   進行業務操作
            //lucy少100
            userDao.reduceMoney();

            //模拟異常
            int i=10/0;

            //mary多100
            userDao.addMoney();
            //第三步 沒有發生異常,送出事務
//        } catch (Exception e) {
            //第四步 出現異常,事務復原

//        }
    }
}      
testTX
@Test
    public void testAccount1(){

        ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }      

事務操作(完全注解聲明式事務管理)

1、建立配置類,使用配置類替代xml配置檔案

spring5/建立config包/建立TxConfig
package com.atguigu.spring5.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(basePackages = "com.atguigu")    //元件掃描
@EnableTransactionManagement    //開啟事務
public class TxConfig {
    //建立資料庫連接配接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    
    //JdbcTemplate對象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //到IOC容器中根據類型找到dataSource
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        //注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    
    //建立事務管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}      
UserService
package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;

    //轉賬的方法
    public void accountMoney(){
//        try {
            //第一步   開啟事務

            //第二部   進行業務操作
            //lucy少100
            userDao.reduceMoney();

            //模拟異常
            int i=10/0;

            //mary多100
            userDao.addMoney();
            //第三步 沒有發生異常,送出事務
//        } catch (Exception e) {
            //第四步 出現異常,事務復原

//        }
    }
}      
testTX
@Test
    public void testAccount2(){

        ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }