• Spring 事务处理、整合web


    录:

    1、回顾事务
    2、spring事务管理
    3、事务案例--转账
    4、手动管理事务(了解)
    5、工厂bean 生成代理:半自动(了解)
    6、AOP配置事务--基于xml【掌握】
    7、AOP配置事务--基于注解【掌握】
    8、整合web--在web.xml中配置spring容器
    9、从Servlet中获取spring容器
    10、SSH整合--jar包
    11、spring整合hibernate:没有hibernate.cfg.xml 【重点】
    12、spring整合struts:struts创建action 【重点】

    1、回顾事务    <--返回目录

        * 事务:一组业务操作ABCD,要么全部成功,要么全部不成功。
        * 特性:ACID
            - 原子性:整体
            - 一致性:完成
            - 隔离性:并发
            - 持久性:结果
        * 隔离问题:
            - 脏读:一个事务读到另一个事务没有提交的数据
            - 不可重复读:一个事务读到另一个事务已提交的数据(update)
            - 虚读(幻读):一个事务读到另一个事务已提交的数据(insert)
        * 隔离级别:
            - read uncommitted:读未提交。存在3个问题
            - read committed:读已提交。解决脏读,存在2个问题
            - repeatable read:可重复读。解决:脏读、不可重复读,存在1个问题。
            - serializable :串行化。都解决,单事务。
        * mysql 事务操作

    ABCD 一个事务
    Connection conn = null;
    try{
      //1 获得连接
      conn = ...;
      //2 开启事务
      conn.setAutoCommit(false);
      A
      B
      C
      D
      //3 提交事务
      conn.commit();
    } catche(){
      //4 回滚事务
      conn.rollback();
    }

        * mysql 事务操作--Savepoint

    需求:AB(必须),CD(可选) 
    Connection conn = null;
    Savepoint savepoint = null;  //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)
    try{
      //1 获得连接
      conn = ...;
      //2 开启事务
      conn.setAutoCommit(false);
      A
      B
      savepoint = conn.setSavepoint();
      C
      D
      //3 提交事务
      conn.commit();
    } catche(){
      if(savepoint != null){   //CD异常
         // 回滚到CD之前
         conn.rollback(savepoint);
         // 提交AB
         conn.commit();
      } else{   //AB异常
         // 回滚AB
         conn.rollback();
      }
    }

    2、spring事务管理    <--返回目录

        * 涉及事务,首先需要jar包:spring-tx-3.2.0.RELEASE.jar
        * 三个顶级接口
            - PlatformTransactionManager  平台事务管理器,spring要管理事务,必须使用事务管理器
                进行事务配置时,必须配置事务管理器。
            - TransactionDefinition:事务详情(事务定义、事务属性),spring用于确定事务具体详情,
                例如:隔离级别、是否只读、超时时间 等
                进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。
            - TransactionStatus:事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
                spring底层根据状态进行相应操作。
        * 以后,我们需要做的:配置事务管理器,配置事务详情,事务状态我们不管
        
        * 常见的事务管理器
            - DataSourceTransactionManager,jdbc开发时事务管理器,采用JdbcTemplate
                ** 需要导spring-jdbc-3.2.0.RELEASE.jar
            - HibernateTransactionManager,hibernate开发时事务管理器,整合hibernate
                ** 需要导spring-orm-3.2.0.RELEASE.jar
                
        * 事务管理器的api详解
            TransactionStatus getTransaction(TransactionDefinition definition):事务管理器 通过"事务详情",
                获得"事务状态",从而管理事务。
            void commit(TransactionStatus status)  根据状态提交
            void rollback(TransactionStatus status) 根据状态回滚
        
        * 事务状态TransactionStatus的方法
            isNewTranction():是否是新的事务
            hasSavepoint():是否有保存点
            setRollbackOnly():设置回滚
            isRollbackOnly():是否回滚
            flush():刷新
            isCompleted():是否完成
            
        * 事务详情TransactionDefinition
            - getName()方法:配置事务详情名称,一般取方法名称,例如save、add*等
            - isReadOnly():是否只读,一般增删改:读写,查询:只读
            - getTimeout():获得超时时间
            - getIsolationLevel():隔离级别
            - getPropagationBehavior():传播行为
            
            - TIMEOUT_DEFAULT:默认超时时间,默认值-1,使用数据库底层的超时时间
            - ISOLATION_DEFAULT:隔离级别 0 1 2 4 8
            - ISOLATION_READ_UNCOMMITTED
            - ISOLATION_READ_COMMITTED
            - ISOLATION_REPEATABLE_READ
            - ISOLATION_SERIALIZABLE
            
            - 传播行为:在两个业务之间如何共享事务  A调用B,设置B的传播行为
                ** PROPAGATION_REQUIRED【默认值】  required 必须:支持当前事务,A有事务,B将使用该事务;
                    如果A没有事务,B将创建一个新的事务
                ** PROPAGATION_SUPPORTS supports 支持:支持当前事务,A有事务,B将使用该事务;
                    如果A没有事务,B将以非事务执行
                ** PROPAGATION_MANDATORY mandatory 强制:支持当前事务,A有事务,B将使用该事务;
                    如果A没有事务,B将抛异常
                
                ** PROPAGATION_REQUIRES_NEW【以后常用】 必须新的:如果A有事务,将A的事务挂起,
                    B创建一个新的事务;如果A没有事务,B创建新的事务
                    
                ** PROPAGATION_NOT_SUPPORTED 不支持:如果A有事务,将A的事务挂起,B将以非事务执行;
                    如果A没有事务,B将以非事务执行
                    
                ** PROPAGATION_NEVER 不支持事务,也不支持当前事务:如果A有事务,B将抛异常;
                    如果A没有事务,B以非事务执行
                
                ** PROPAGATION_NESTED【也要掌握】 嵌套:A和B底层采用保存点机制,执行嵌套事务

    3、事务案例--转账    <--返回目录

      创建表

    create database db_test1 default character set utf8;
    use db_test1;
    create table t_account(
      id int primary key auto_increment,
      username varchar(50),
      money int
    )engine innodb;
    insert into t_account(username,money) values('jack','1000');
    insert into t_account(username,money) values('rose','1000');

      导入jar包

    ** 核心:4+1
    ** aop :4 (aop联盟、spring aop、aspectjweaver规范、spring aspect)
    ** jdbc和事务相关:2(jdbc、tx)
    ** 驱动:mysql
    ** 连接池:c3p0

      dao层:接口和实现类

    public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
        @Override
        public void out(String outer, Integer money) {
            this.getJdbcTemplate().update("update account set money = money - ? 
                where username = ?", money,outer);
        }
        @Override
        public void in(String inner, Integer money) {
            this.getJdbcTemplate().update("update account set money = money + ? 
                where username = ?", money,inner);
        }
    }

      service层:接口和实现类

    public class AccountServiceImpl implements AccountService {
        private AccountDao accountDao;
        public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }
        @Override
        public void transfer(String outer, String inner, Integer money) {
            accountDao.out(outer, money);  //outer减钱
            //断电,这样就会导致:outer减钱,但是inter不加钱
            //int i = 1/0;
            accountDao.in(inner, money);  //inter加钱
        }
    }

      spring配置

    <!-- 1 数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>
    
    <!-- 2 dao  依赖JdbcTemplate,继承JdbcDaoSupport,需要注入数据源
    -->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 3 service 依赖dao层,需要注入accountDao-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

      测试

    @Test
    public void demo01(){
        String xmlPath = "applicationContext.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService =  (AccountService) applicationContext.getBean
            ("accountService");
        accountService.transfer("jack", "rose", 100);
    }

      

    4、手动管理事务(了解)    <--返回目录

    * spring底层使用TransactionTemplate事务模板进行操作
    * 操作
        - service需要获得TransactionTemplate
        - 所以,在spring配置TransactionTemplate,并注入到service
        - 模板TransactionTemplate需要注入事务管理器
        - 所以,需要配置事务管理器DataSourceTransactionManager
        - 事务管理器需要注入DataSource
        1) 配置数据源
        2) 配置事务管理器(依赖数据源)
        3) 配置模板TransactionTemplate(依赖事务管理器)
        4) 配置service(依赖模板TransactionTemplate)

    5、工厂bean 生成代理:半自动(了解)    <--返回目录

      spring提供了管理事务的代理工厂bean  TransactionProxyFactoryBean
        1) spring 配置一个代理<bean id="" class="TransactionProxyFactoryBean"/>
        2) getBean(TransactionProxyFactoryBean的id值)获得代理对象

    spring配置文件:

    <!-- 4 service 代理对象 
    4.1 proxyInterfaces 接口 
    4.2 target 目标类
    4.3 transactionManager 事务管理器
    4.4 transactionAttributes 事务属性(事务详情)
        prop.key :确定哪些方法使用当前事务配置
        prop.text:用于配置事务详情
            格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
                传播行为        隔离级别    是否只读        异常回滚        异常提交
            注意:如果这里配置readOnly只读,若执行增删改,会报错
                  +Exception:表示有异常,仍提交。可能导致,事务只执行一部分业务
            例如:
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默认传播行为,
                    和隔离级别
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只读
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.
                    ArithmeticException</prop>  有异常仍提交
    -->
    <bean id="proxyAccountService" class="org.springframework.transaction.interceptor.
        TransactionProxyFactoryBean">
        <property name="proxyInterfaces" value="com.itheima.service.AccountService"></property>指定接口
        <property name="target" ref="accountService"></property>   【指定一个目标类】
        <property name="transactionManager" ref="txManager"></property>  指定事务管理器
        <property name="transactionAttributes">  指定事务详情
            <props>
                <!-- 指定目标类的transfer()方法使用当前事务配置 -->
                <prop key="【目标类方法】transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
            </props>
        </property>
    </bean>
    
    <!-- 5 事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

      

    6、AOP配置事务--基于xml【掌握】    <--返回目录

    在spring xml 配置aop 自动生成代理,进行事务的管理,三步
        1)配置管理器
        2)配置事务详情
        3)配置aop

    <!-- 4 事务管理 -->
    <!-- 4.1 事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 4.2 事务详情(事务通知)  , 在aop筛选基础上,对ABC三个确定使用什么样的事务。例如:AC读写、B只读 等
        <tx:attributes> 用于配置事务详情(属性属性)
            <tx:method name=""/> 详情具体配置
                propagation 传播行为 , REQUIRED:必须;REQUIRES_NEW:必须是新的
                isolation 隔离级别
    -->
    <tx:advice id="txAdvice" transaction-manager="txManager">  
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 4.3 AOP编程,目标类有ABCD(4个连接点),切入点表达式 确定增强的连接点,从而获得切入点:ABC -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
    </aop:config>

    7、AOP配置事务--基于注解【掌握】    <--返回目录

      步骤: 

      1)配置事务管理器,将并事务管理器交予spring
      2)在目标类或目标方法添加注解即可
                    ** 在目标类上配,则作用整个类;在目标方法上配,则作用于该方法
                    ** @Transactional
                    ** @Transactional(propagation=Propagation.REQUIRED , isolation = Isolation.DEFAULT)

      在applicationContext.xml中配置

    <!-- 4 事务管理 -->
    <!-- 4.1 事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 4.2 将管理器交予spring 
        * transaction-manager 配置事务管理器
        * proxy-target-class  true:底层强制使用cglib 代理
    -->
    <tx:annotation-driven transaction-manager="txManager"/>

    8、整合web--在web.xml中配置spring容器    <--返回目录

    * 以前测试都是new出spring容器,例如:
            String xmlPath = "applicationContext.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
            accountService.transfer("jack", "rose", 1000);
        * 但是spring容器创建一次就够了    
            
        * 导入jar包 spring-web
        * 所以,为了让spring配置文件在服务器第一次启动就加载,在web.xml中配置

    <!-- 确定spring配置文件位置 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    
    <!-- 配置spring监听器,加载xml配置文件 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

      

    9、从Servlet中获取spring容器    <--返回目录

    * 在Servlet中获取spring容器,从而可以使用
        - Spring把WebApplicationContext(XmlWebApplicationContext是默认实现类)放在了ServletContext中,
            ServletContext也是一个“容器”,也是一个类似Map的结构,而WebApplicationContext在ServletContext中
            的KEY就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
            我们如果要使用WebApplicationContext则需要从ServletContext取出,Spring提供了一个
            WebApplicationContextUtils类,可以方便的取出WebApplicationContext,
            只要把ServletContext传入就可以了。
        ---------------------
        方法一:
            ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
            ac.getBean("beanId");

        说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。

        方法二:通过Spring提供的工具类获取ApplicationContext对象
            ApplicationContext ac1 = WebApplicationContextUtils
                    .getRequiredWebApplicationContext(ServletContext sc);
            ApplicationContext ac2 = WebApplicationContextUtils
                    .getWebApplicationContext(ServletContext sc);
            ac1.getBean("beanId");
            ac2.getBean("beanId");

        说明:这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,
            然后在通过它获取需要的类实例。
            
        上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。

        其中 servletContext sc 可以具体 换成 servlet.getServletContext()或者 this.getServletContext()
        或者 request.getSession().getServletContext(); 另外,由于spring是注入的对象放在
        ServletContext中的,所以可以直接在ServletContext取出 WebApplicationContext 对象:
        WebApplicationContext webApplicationContext = (WebApplicationContext)servletContext
            .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

        ---------------------
        【总结:通过ServletContext对象获取Spring容器】
        //方式1
        ApplicationContext applicationContext=(ApplicationContext)this.getServletContext()
            .getAtt·ribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        //方式2
        ApplicationContext applicationContext=WebApplicationContextUtils
                .getWebApplicationContext(this.getServletContext());
        //然后在Servlet中可以使用spring容器--applicationContext了

    10、SSH整合--jar包    <--返回目录

      最好新建一个文件夹,然后往里面添加jar包,然后添加到项目里
        struts2:2.3.15.3
        hibernate : 3.6.10
        spring: 3.2.0

        * jar包整合
            - struts2:共13个
            - spring
                ** 核心 4+1:beans、core、context、expression,commons-logging (struts已经导入)
                ** aop相关 4个:aop联盟、spring-aop 、aspect规范、spring-aspect
                ** 数据库db 2个:spring-jdbc、spring-tx
                ** 整合jUnit:spring-test
                ** 整合web:spring-web
                ** 整合hibernate:spring-orm
                ** 驱动:mysql
                ** 连接池:c3p0

                共4+4+2+5=15
                
            - hibernate
                ** 核心 1个:hibernate3.jar
                ** 必须:6个
                ** jpa规范 1个
        
                ** 整合log4j  
                    导入 log4j...jar (struts已经导入)
                    整合(过渡):slf4j-log4j12-1.7.5.jar

                ** 二级缓存
                    核心:ehcache-1.5.0.jar
                    依赖:backport-util-concurrent-2.1.jar和commons-logging(存在)

                共8+1+2=11    
                
            - spring整合hibernate: spring-orm前面写了
              struts整合spring:struts2-spring-plugin-2.3.15.3.jar

            - 所以,整合ssh共:13+15+11+1=40个 删除一个重复的javassist,最终39个


    11、spring整合hibernate:没有hibernate.cfg.xml 【重点】    <--返回目录

        * 与使用jdbcTemplate类似
        * dao层,继承HibernateDaoSupport
            // 底层需要SessionFactory,自动创建HibernateTemplate模板
            public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
                @Override
                public void save(User user) {
                    this.getHibernateTemplate().save(user);
                }
            }
        
        * 使用c3p0数据源,数据源4大参数存放到properties文件中
            新建jdbcinfo.properties文件,添加一些内容

    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.jdbcUrl=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8
    jdbc.user=root
    jdbc.password=

           
        * applicationContext.xml文件配置

    <!-- 1.1 加载properties文件 -->
    <context:property-placeholder location="classpath:com/itheima/f_properties/jdbcInfo.properties"/>
    <!-- 1.2 配置数据源 -->
    <bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password"  value="${jdbc.password}"></property>
    </bean>
    <!-- 1.3 配置 LocalSessionFactoryBean,获得 ->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
            </props>
        </property>
        <property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property>
    </bean>
    
    <!-- 2 dao,需要注入sessionFactory -->
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    
    <!-- 3 service -->
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

    12、spring整合struts:struts创建action 【重点】    <--返回目录

      配置web.xml

    <!-- 1 确定applicationContext.xml位置 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!-- 2 spring监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 3 struts 前端控制器 -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

      要求:Action类中,必须提供service名称与spring配置文件中<bean id="">的id一致。(如果名称一样,将自动注入)

  • 相关阅读:
    新基建的福音:智慧楼宇可视化监控系统引领智能化新时代
    基于 HTML5 和 WebGL 的地铁站 3D 可视化系统
    基于 HTML5 WebGL 的医疗物流系统
    基于 HTML5 的 PID-进料系统可视化界面
    基于 HTML5 Canvas 的可交互旋钮组件
    基于 HTML5 WebGL 的民航客机飞行监控系统
    基于 HTML5 Canvas 的元素周期表展示
    基于 HTML5 换热站可视化应用
    基于 HTML5 WebGL 的 3D 智慧隧道漫游巡检
    【python 爬虫】fake-useragent Maximum amount of retries reached解决方案
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/13759316.html
Copyright © 2020-2023  润新知