zoukankan      html  css  js  c++  java
  • Spring(七)-事务操作

    一、事务相关概念

    1)事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的完整性和一致性.

    2)事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用

    3)事务的四个关键属性(ACID)

    • 原子性(atomicity): 事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
    • 一致性(consistency): 一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
    • 隔离性(isolation): 可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
    • 持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.

    二、Spring事务管理

    2.1、Spring事务介绍

    1)事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

    2)在 Spring 进行事务管理操作有两种方式

    • 编程式事务管理
    • 声明式事务管理(使用)

    3)声明式事务管理

    • 基于注解方式(使用)
    • 基于 xml 配置文件方式

    4)在 Spring 进行声明式事务管理,底层使用 AOP 原理

    5)Spring 事务管理 API

    提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

    image

    2.2、注解声明式事务管理

    以转账为例:

    1)Dao方法:

    UserDao:

    package com.dianchou.spring.tx;
    
    /**
     * @author lawrence
     * @create 2020-07-09 11:11
     */
    public interface UserDao {
    
        //账户转出
        public void reduceBalance();
    
        //账户转入
        public void addBalance();
    }
    

    UserDaoImpl:

    package com.dianchou.spring.tx;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    /**
     * @author lawrence
     * @create 2020-07-09 11:11
     */
    
    @Repository
    public class UserDaoImpl implements UserDao{
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void reduceBalance() {
            String sql = "update account set balance=balance-? where username = ?";
            jdbcTemplate.update(sql,100,"Tom");
        }
    
        @Override
        public void addBalance() {
            String sql = "update account set balance=balance+? where username = ?";
            jdbcTemplate.update(sql,100,"Jerry");
        }
    }
    

    2)Service方法

    package com.dianchou.spring.tx;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @author lawrence
     * @create 2020-07-09 11:10
     */
    
    //@Transactional,
    //(1)这个注解添加到类上面,也可以添加方法上面
    //(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
    //(3)如果把这个注解添加方法上面,为这个方法添加事务
    @Service
    @Transactional
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        public void accountBalance(){
            userDao.reduceBalance();
    //        int i = 10 / 0;
            userDao.addBalance();
        }
    }
    

    3)配置文件

    <?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:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
        <!--开启组件扫描-->
        <context:component-scan base-package="com.dianchou.spring.tx"></context:component-scan>
    
        <!--配置数据库连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="${prop.url}" />
            <property name="username" value="${prop.userName}" />
            <property name="password" value="${prop.password}" />
            <property name="driverClassName" value="${prop.driverClass}" />
        </bean>
    
        <!--配置JdbcTemplate对象并注入datasource-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!--注入dataSource-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--开启事务注解-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    </beans>

    4)测试

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

    2.3、事务配置相关参数

    在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

    image

    2.3.1、propagation:事务传播行为

    当事务方法被另一个事务方法调用时, 必须指定事务应该如何传播. 例如: 方法可能继续在现有事务中运行, 也可能开启一个新事务, 并在自己的事务中运行.

    事务的传播行为可以由传播属性指定. Spring 定义了 7  种类传播行为.

    image

    image

    2.3.2、ioslation:事务隔离级别

    关于三个读问题:

    1. 脏读:一个未提交事务读取到另一个未提交事务的数据
    2. 不可重复读:一个未提交事务读取到另一提交事务修改数据
    3. 虚读:一个未提交事务读取到另一提交事务添加数据

    解决:通过设置事务隔离级别,解决读问题

    image

    image

    2.3.3、timeout:超时时间

    (1)事务需要在一定时间内进行提交,如果不提交进行回滚

    (2)默认值是 -1 ,设置时间以秒单位进行计算

    2.3.4、readOnly:是否只读

    (1)读:查询操作,写:添加修改删除操作

    (2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作

    (3)设置 readOnly 值是 true,设置成 true 之后,只能查询

    2.3.5、rollbackFor:回滚

    (1)设置出现哪些异常进行事务回滚

    2.3.6、noRollbackFor:不回滚

    (1)设置出现哪些异常不进行事务回滚

    2.4、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:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
        <!--开启组件扫描-->
        <context:component-scan base-package="com.dianchou.spring.tx"></context:component-scan>
    
        <!--配置数据库连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="${prop.url}" />
            <property name="username" value="${prop.userName}" />
            <property name="password" value="${prop.password}" />
            <property name="driverClassName" value="${prop.driverClass}" />
        </bean>
    
        <!--配置JdbcTemplate对象并注入datasource-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!--注入dataSource-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--配置通知-->
        <tx:advice id="txadvice">
            <!--配置事务参数-->
            <tx:attributes>
                <!--指定哪种规则的方法上面添加事务-->
                <tx:method name="accountBalance" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
    
        <!--配置切入点和切面-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="pt" expression="execution(* com.dianchou.spring.tx.UserService.*(..))"/>
            <!--配置切面-->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
        </aop:config>
    
        <!--开启事务注解-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    </beans>
    

    2.5、完全注解声明式事务管理

    package com.dianchou.spring.tx;
    
    import com.alibaba.druid.pool.DruidDataSource;
    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.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.util.Properties;
    
    /**
     * @author lawrence
     * @create 2020-07-09 16:08
     */
    
    @Configuration  //配置类
    @ComponentScan(basePackages = {"com.dianchou.spring.tx"})
    @EnableTransactionManagement
    public class TxConfig {
    
        /**
         * 创建数据库连接池
         */
        @Bean
        public DruidDataSource getDruidDataSource() throws IOException {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://47.110.61.153:3306/mybatis");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            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;
        }
    }
    
  • 相关阅读:
    vue-cli3初尝试之路径别名配置
    nodejs之koa-router与koa-body搭配使用
    nodejs之crypto加密算法
    nodejs之glob与globby
    vuecli3初尝试(转载)
    python之线程同步
    python之多线程通信
    python之通过thread来实现多进程
    U盘启动盘安装Mac OS
    Windows环境下制作MACOS X U盘安装盘
  • 原文地址:https://www.cnblogs.com/hujinzhong/p/13272361.html
Copyright © 2011-2022 走看看