Spring的事务管理

Spring中的事务

  • Spring声明式事务管理
  •     1.  XML配置
        2.注解方式
    

  • Spring与Hibernate整合
  • SSH整合
  • 程序中事务控制

    用户访问->action->Service->Dao
    一个业务成功,调用的service是执行成功的,意味着service中调用的所有dao是执行成功的 。
    事务应该在service层统一控制。
    模拟:在service中调用2次dao,希望其中一个dao执行失败,整个操作要回滚

    开发步骤:
    后台环境准备
    1.数据表:entity/dao/service
    2.dao的实现
    3.对象创建都由Spring容器完成

    事务控制

    一:编程式事务控制

    自己手动控制事务,就叫做编程式事务控制
    
    //设置手动控制事务
        jdbc代码:jdbc是拿到connection对象,然后setAutoCommit(false)
    
    Hibernate:
        Session.beginTransaction();
    

    细粒度的事务控制,可以对指定的方法、指定的几行添加事务控制
    二:声明式事务控制
    Spring提供了事务的管理,这个就叫做声明式事务管理。
    即定义了一个事务。
    Spring提供了对事务控制的实现,用户如果想实现Spring声明式事务管理,只需要在配置文件中配置即可,不想使用直接移除即可,这个实现了对事务控制最大程度的 解耦
    Spring声明式事务管理,核心实现就是基于Aop;
    只能对整个方法应用事务,不能对方法的某几行应用事务,因为Aop拦截的是方法

    Spring声明式事务管理器类

    一:配置实现

    bean.xml

    配置事务管理器类
    
     <!--5. Spring事务管理配置 -->
    
             <!--5.1 配置事务管理器类 -->
             <bean id="txManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    
                <property name="dataSource" ref="dataSource"></property>
    
             </bean>
             <!--5.2配置事务增强  -->
             <tx:advice id="txAdvice" transaction-manager="txManager">
                <tx:attributes>
                    <tx:method name="get*" read-only="true"/>
                    <tx:method name="find*" read-only="true"/>
                        <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception"/>
                </tx:attributes>
             </tx:advice>
    
    
             <!-- 5.3AOP配置 拦截哪些方法+应用上面的事务增强配置-->
             <aop:config>
                <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*(..))" id="pt"/>
                <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
             </aop:config>
    

    //事务失败的原因:
    1.save方法有参数,在切入点配置execution()时候DeptService.*(..)时候没有加..,拦截的是不带参数的save(),而不是save(Dept dept),因此事务执行失败
    2.jdbc技术:DataSourceTransactionManager
    Hibernate技术:HibernateTransaction

    二:注解方式实现

    使用注解实现Spring
    1.必须引入aop相关jar文件
    2.bean.xml指定注解方式实现声明式事务管理及应用的事务管理器类
    3.在需要添加事务控制的地方,写上transactional

    @Transactional注解:
    1.应用事务的注解
    2.定义到方法上,当前方法应用spring的声明式事务
    3.定义到类上,当前类的所有方法都应用spring声明式事务管理
    4.定义到父类上,当执行父类时候应用事务

    bean.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:p="http://www.springframework.org/schema/p"
        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-2.5.xsd">
    
    
          <!--数据源对象:c3p0连接池 -->
          <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;useSSL=false"></property>
    
            <property name="user" value="root"></property>
                <property name="password" value="qqaazz"></property>
            <property name="initialPoolSize" value="3"></property>
                <property name="maxPoolSize" value="10"></property>
            <property name="maxStatements" value="100"></property>
                <property name="acquireIncrement" value="2"></property>
    
          </bean>
    
    
    
          <!-- jdbctemplate工具类实例 -->
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"></property> 
          </bean>
    
          <!-- 事务管理器类 -->
          <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
    
          </bean>
    
          <!--开启注解扫描  -->
          <context:component-scan base-package="cn.itcast.b_anno">
          </context:component-scan>
    
         <!-- 注解方式实现事务,指定注解方式实现事务 -->
         <tx:annotation-driven transaction-manager="txManager"/>
    
    </beans>

    DeptDao.java

    package cn.itcast.b_anno;
    import javax.annotation.Resource;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    /**
     * 使用spring的jdbc
     */
    @Repository
    public class DeptDao {
        @Resource
        private JdbcTemplate jdbcTemplate;
    
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        public JdbcTemplate getJdbcTemplate() {
            return jdbcTemplate;
        }
        public void save(Dept dept){
            String sql="insert into t_dept(deptName) values(?);";
            jdbcTemplate.update(sql,dept.getDeptName());
        }
    }

    DeptService.java

    package cn.itcast.b_anno;
    
    import javax.annotation.Resource;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class DeptService {
        @Resource
            private DeptDao deptDao;    
    
            public DeptDao getDeptDao() {
                return deptDao;
            }
            public void setDeptDao(DeptDao deptDao) {
                this.deptDao = deptDao;
            }
    
            @Transactional
            public void save(Dept dept) {
                //第一次调用         
                deptDao.save(dept);
    //          int i=1/0;
                //第二次调用
                deptDao.save(dept);
            }
    }
    

    测试类App.java

    package cn.itcast.b_anno;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class App {
        @Test
        public void testApp() {
            ApplicationContext ac1=new ClassPathXmlApplicationContext("cn/itcast/b_anno/bean.xml");
            Dept dept=new Dept();
            dept.setDeptName("测试部门");
    
            DeptService deptService=(DeptService)ac1.getBean("deptService");
            deptService.save(dept);
        }
    }

    @Transactional(
    readonly=false,
    timeout=-1 //事务超时时间,但是底层超时是由数据库决定的
    noRollbackFor=ArithmeticException.class //遇到这种数学异常不回滚
    isolation=Isolation.Default, 数据库的隔离级别
    propadation=Propagation.REQUIRED //事务的传播行为
    REQUIRED:业务方法需要在一个事务中运行,如果方法运行时,已经处在一个事务中那么加入到该事务,否则为自己创建一个新的 事务;
    REQUIRED_NEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务,如果方法已经运行在一个事务中,则原有的事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。

    )

        class Log{
            Propagation.REQUIRED;
            insertLog();
        }
    
    
        void saveDept(){
            // 本身有事务,定义了一个required,那么假如同一个事务。但是方法执行失败也需要假如日志,所以需要把insertLog()写成
            Propagation.REQUIED_NEW;
            //那么外面saveDept是一个事务,里面的insertLog也是一个事务
            insertLog();
            //此时发生异常的话,如果是REQUIRED会回滚,如果是REQUIRED_NEW那么不会回滚。
            saveDept();
        }

    了解容器的相关方法

    1.根据bean.xml配置,创建容器对象
    //根据多个配置文件的路径,创建容器对象
    1️⃣ApplicationContext ac=new ClassPathXmlApplicationContext(new String[]{})
    2️⃣ApplicationContext ac=new ClassPathXmlApplicationContext(“cn/bean.xml”)

    2.从容器中获取指定名称的bean对象
    DeptDao deptdao=(DeptDao)ac.getbean(“depedao”);
    还可以根据类型获取
    //该类型在IOC容器中只能有一个,否则报错。
    DeptDao deptDao=ac.getBean(DeptDao.class);
    //使用泛型,不需要强转
    DeptDao deptDao=ac.getBean(“deptDao”,DeptDao.class);

    4.获取容器中bean对象的数量
    ac.getBeanDefinitionCount();

    5.获取容器中bean对象的名字
    String[] names=ac.getBeanDefinitionNames();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值