• day35_Spring学习笔记_03


    一、事务管理

    1.1、回顾事务

    • 事务:一组业务操作ABCD,要么全部成功,要么全部不成功。
    • 特性:ACID
      原子性:整体
      一致性:完成
      隔离性:并发
      持久性:结果
    • 隔离问题:
      脏读:一个事务读到另一个事务没有提交的数据。读到的是假的数据。
      不可重复读:一个事务读到另一个事务已提交的数据(update)。每次读到的结果不一样。
      虚读(幻读):一个事务读到另一个事务已提交的数据(insert)。读到的数据变多了。
    • 隔离级别:
      read uncommitted:读未提交。存在3个问题。
      read committed:读已提交。解决脏读,存在2个问题。
      repeatable read:可重复读。解决脏读、不可重复读,存在1个问题。
      serializable:串行化。都解决,单事务。
    • mysql 事务操作(简单)
    ABCD 是一个事务,有4个业务
    Connection conn = null;
    try {
      // 1、获得连接
      conn = ...;
      // 2、开启事务
      conn.setAutoCommit(false);
      A
      B
      C
      D
      // 3、提交事务
      conn.commit();
    catch() {
      // 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();
    catch() {
      if (savepoint != null) {   // 说明CD异常
         // 回滚到CD之前
         conn.rollback(savepoint);
         // 提交AB
         conn.commit();
      } else {   // 说明AB异常
         // 回滚AB之前
         conn.rollback();
      }
    }

    1.2、事务管理介绍

    1.2.1、导入jar包

    transaction --> tx

    1.2.2、三个顶级接口

    • PlatformTransactionManager 平台事务管理器,spring要管理事务,必须使用事务管理器
      进行事务配置时,必须配置事务管理器
    • TransactionDefinition 事务详情(事务定义、事务属性),spring用于确定事务的具体详情
      例如:隔离级别、是否只读、超时时间 等等。
      进行事务配置时,必须配置事务详情。spring将配置项封装到该对象实例。
    • TransactionStatus 事务状态,spring用于记录当前事务的运行状态。
      例如:是否有保存点,事务是否完成。
      spring底层根据不同的运行状态进行相应操作。跟我们没有关系,我们只需要知道即可。

    1.2.3、PlatformTransactionManager 事务管理器

    • 导入jar包:我们需要的是平台事务管理器的实现类
    • 常见的事务管理器(必须记住)
      DataSourceTransactionManager jdbc开发时使用的事务管理器,采用JdbcTemplate
      HibernateTransactionManager hibernate开发时使用的事务管理器,整合hibernate时使用
    • api详解
      TransactionStatus getTransaction(TransactionDefinition definition) “事务管理器”通过“事务详情”,获得“事务状态”,从而管理事务。
      void commit(TransactionStatus status) 根据状态提交
      void rollback(TransactionStatus status) 根据状态回滚

    1.2.4、TransactionStatus 事务状态(了解)

    • 事务状态

    1.2.5、TransactionDefinition 事务详情

    • 事务详情

    传播行为:在两个业务之间如何共享事务。每个值的详解如下:

    • PROPAGATION_REQUIRED , required , 必须【默认值】
      • 支持当前事务,A如果有事务,B将使用该事务。
      • 如果A没有事务,B将创建一个新的事务。即B永远处在事务中。
    • PROPAGATION_SUPPORTS , supports , 支持
      • 支持当前事务,A如果有事务,B将使用该事务。
      • 如果A没有事务,B将以非事务执行。
    • PROPAGATION_MANDATORY , mandatory , 强制
      • 支持当前事务,A如果有事务,B将使用该事务。
      • 如果A没有事务,B将抛出异常。
    • PROPAGATION_REQUIRES_NEW , requires_new , 必须新的
      • 如果A有事务,将A的事务挂起,B将创建一个新的事务。
      • 如果A没有事务,B将创建一个新的事务。
    • PROPAGATION_NOT_SUPPORTED , not_supported , 不支持
      • 如果A有事务,将A的事务挂起,B将以非事务执行。
      • 如果A没有事务,B将以非事务执行。
    • PROPAGATION_NEVER , never , 从不
      • 如果A有事务,B将抛出异常。
      • 如果A没有事务,B将以非事务执行。
    • PROPAGATION_NESTED , nested , 嵌套
      • A和B底层采用保存点机制,形成嵌套事务。

    掌握:PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED

    1.3、事务案例:转账

    1.3.1、搭建环境

    1.3.1.1、创建表

    CREATE DATABASE day35;
    USE day35;

    CREATE TABLE account(
      id INT PRIMARY KEY AUTO_INCREMENT,
      username VARCHAR(50),
      money INT
    );

    INSERT INTO account(username, money) VALUES('jack''10000');
    INSERT INTO account(username, money) VALUES('rose''10000');

    1.3.1.2、导入jar包

    • 核心:4 + 1
    • aop:4 (aop 联盟、spring aop、aspectj 规范、spring aspect)
    • 数据库:2(jdbc/tx)
    • 驱动:mysql
    • 连接池:c3p0

    1.3.1.3、dao层

    AccountDao.java

    public interface AccountDao {
        /**
         * 汇款
         * 
         * @param outer
         * @param money
         */

        public void out(String outer, Integer money);

        /**
         * 收款
         * 
         * @param inner
         * @param money
         */

        public void in(String inner, Integer money);
    }

    AccountDaoImpl.java

    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);
        }
    }

    1.3.1.4、service层
    AccountService.java

    public interface AccountService {
        /**
         * 转账
         * 
         * @param outer
         * @param inner
         * @param money
         */

        public void transfer(String outer, String inner, Integer money);
    }

    AccountServiceImpl.java

    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);

            // 断电
            // int i = 1/0; // 断电会出现事务问题

            accountDao.in(inner, money);
        }
    }

    1.3.1.5、spring配置
    为了更加接近实际开发,配置文件的名称改为 applicationContext.xml,配置文件的位置放在 src目录下。
    applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
                                  http://www.springframework.org/schema/beans/spring-beans.xsd
                                  http://www.springframework.org/schema/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd"
    >
                          
        <!-- datasource -->
        <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/day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- service -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>

    </beans>

    1.3.1.6、测试
    TestApp.java

    package com.itheima;

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    import com.itheima.service.AccountService;

    public class TestApp {
        @Test
        public void demo01() {
            String xmlPath = "applicationContext.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            AccountService accountService = (AccountService) applicationContext.getBean("accountService");

            accountService.transfer("jack""rose"100);
        }
    }

    1.3.2、手动管理事务(了解)

    • spring底层使用 TransactionTemplate事务模板 来进行操作的。
    • 如何操作呢?步骤如下:
      • 1、service层需要获得 TransactionTemplate事务模板
      • 2、spring就需要配置模板,并注入给service层
      • 3、配置模板又需要注入事务管理器
      • 4、配置事务管理器 DataSourceTransactionManager,又需要注入DataSource

    1.3.2.1、修改service层代码
    AccountServiceImpl.java

    package com.itheima.service.impl;

    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;

    import com.itheima.dao.AccountDao;
    import com.itheima.service.AccountService;

    public class AccountServiceImpl implements AccountService{

        private AccountDao accountDao;
        public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }

        // 需要Spring注入模板
        private TransactionTemplate transactionTemplate;
        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
            this.transactionTemplate = transactionTemplate;
        }

        @Override
        public void transfer(final String outer, final String inner, final Integer money) {

            transactionTemplate.execute(new TransactionCallbackWithoutResult() {

                @Override
                protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                    accountDao.out(outer, money);
                    // 断电
                    int i = 1/0// 断电会出现事务问题
                    accountDao.in(inner, money);
                }
            });
        }
    }

    1.3.2.2、修改spring配置
    applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
                                  http://www.springframework.org/schema/beans/spring-beans.xsd
                                  http://www.springframework.org/schema/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd"
    >
                          
        <!-- datasource -->
        <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/day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- service -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
            <property name="transactionTemplate" ref="transactionTemplate"></property>
        </bean>

        <!-- 创建模板 -->
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="txManager"></property>
        </bean>
        <!-- 配置事务管理器,注意:事务管理器需要事务,而事务从  连接Connection 获得,而  连接Connection 从  连接池DataSource 处获得 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

    </beans>

    1.3.3、使用工厂bean 生成代理:半自动

    • spring提供了管理事务的代理工厂bean:TransactionProxyFactoryBean,操作步骤如下:
      • 1、getBean() 获得代理对象
      • 2、在spring中配置一个代理

    1.3.3.1、spring配置
    applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
                                  http://www.springframework.org/schema/beans/spring-beans.xsd
                                  http://www.springframework.org/schema/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd"
    >
                          
        <!-- datasource -->
        <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/day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- service -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>

        <!-- service 的代理对象 
            4.1 proxyInterfaces 接口 
            4.2 target 目标类
            4.3 transactionManager 事务管理器
            4.4 transactionAttributes 事务属性(事务详情)
                prop.key :确定哪些方法使用当前事务配置
                prop.text :用于配置事务详情
                    格式:PROPAGATION,ISOLATION,readOnly,-Exception,+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="preInterceptors" value="com.itheima.service.AccountService"></property>
            <property name="target" ref="accountService"></property>
            <property name="transactionManager" ref="txManager"></property>
            <property name="transactionAttributes">
                <props>
                    <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>  <!-- 默认传播行为,和默认隔离级别 -->
                </props>
            </property>
        </bean>

        <!-- 事务管理器  -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

    </beans>

    1.3.3.2、测试
    TestApp.java

    package com.itheima;

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    import com.itheima.service.AccountService;

    public class TestApp {
        @Test
        public void demo01() {
            String xmlPath = "applicationContext.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            AccountService accountService = (AccountService) applicationContext.getBean("proxyAccountService");

            accountService.transfer("jack""rose"100);
        }
    }

    1.3.4、AOP 配置基于xml:全自动【掌握】

    • 在spring xml 配置了aop,就会自动生成代理,之后就可以进行事务的管理,操作步骤如下:
      • 1、配置管理器
      • 2、配置事务详情
      • 3、配置aop

    applicationContext.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/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd
                                  http://www.springframework.org/schema/tx 
                                  http://www.springframework.org/schema/tx/spring-tx.xsd"
    >
                            
        <!-- datasource -->
        <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/day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- service -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>

        <!-- 事务管理 -->
        <!-- 4.1 事务管理器 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </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>   

    </beans>

    1.3.5、AOP 配置基于注解:全自动【掌握】

    • 操作步骤如下:
      • 1、配置事务管理器,并将事务管理器交予spring管理
      • 2、在目标类或目标方法添加注解即可 @Transactional

    1.3.5.1、spring配置
    applicationContext.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/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd
                                  http://www.springframework.org/schema/tx 
                                  http://www.springframework.org/schema/tx/spring-tx.xsd"
    >
                            
        <!-- datasource -->
        <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/day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- service -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>

        <!-- 事务管理 -->
        <!-- 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代理
                false :默认的值为false
        -->

        <tx:annotation-driven transaction-manager="txManager" proxy-target-class="false"/>

    </beans>

    1.3.5.2、service 层
    AccountServiceImpl.java

    @Transactional
    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);

            // 断电
            // int i = 1/0; // 断电会出现事务问题

            accountDao.in(inner, money);
        }
    }

    1.3.5.3、事务详情配置


    AccountServiceImpl.java
    @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.DEFAULT)
    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);

            // 断电
            // int i = 1/0; // 断电会出现事务问题

            accountDao.in(inner, money);
        }
    }

    二、整合 Junit

    步骤如下:

    • 导入jar包
      • 基本 :4 + 1
      • 测试:spring-test…jar
    • 1、让Junit去通知spring加载配置文件
    • 2、让spring容器自动进行注入

    TestApp.java

    // 1、让Junit去通知spring加载配置文件
    // 2、让spring容器自动进行注入
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class TestApp {

        @Autowired // 这是与junit整合,不需要在spring xml中进行配置扫描
        private AccountService accountService;

        @Test
        public void demo01() {
            // String xmlPath = "applicationContext.xml";
            // ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            // AccountService accountService = (AccountService) applicationContext.getBean("accountService");

            accountService.transfer("jack""rose"100);
        }
    }

    三、整合 web

    步骤如下:

    0、导入jar包
        spring-web-3.2.0.RELEASE.jar

    1、tomcat启动时就加载配置文件的方案:
        方案1:servlet --> init(ServletConfig) --> <load-on-startup>2
        方案2:filter --> init(FilterConfig) --> web.xml注册过滤器后,就会自动调用初始化
        方案3:listener --> ServletContextListener --> servletContext对象监听
        方案4:spring提供了一个监听器 ContextLoaderListener  --> web.xml (<listener><listener-class>...)
                如果只配置了监听器,则默认加载xml文件的位置为:/WEB-INF/applicationContext.xml

    2、确定配置文件位置,通过系统初始化参数
        ServletContext的初始化参数配,在web.xml文件中进行配置:
            <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </context-param>

    3、从servletContext作用域中获得spring容器(了解即可,很少用)

    步骤二如果没有配置好,会出现的报错截图如下:


    web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
        id="WebApp_ID" version="3.1">

        <display-name>day35_04_Spring_tx</display-name>

      <!-- 确定配置文件位置 -->
      <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>


      <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.itheima.web.servlet.HelloServlet</servlet-class>
      </servlet>

      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
      </servlet-mapping>    

        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>default.html</welcome-file>
            <welcome-file>default.htm</welcome-file>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
    </web-app>

    HelloServlet.java

    public class HelloServlet extends HttpServlet {

        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            // 从application作用域(ServletContext)获得spring容器
            // 方式1: 手动从作用域获取
            ApplicationContext applicationContext = (ApplicationContext) this.getServletContext()
                    .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
            // 方式2:通过工具类获取
            ApplicationContext apppApplicationContext2 = WebApplicationContextUtils
                    .getWebApplicationContext(this.getServletContext());

            // 转账操作
            AccountService accountService = (AccountService) applicationContext.getBean("accountService");
            accountService.transfer("jack""rose"1000);
        }

        @Override
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    }

    四、SSH 整合

    4.1、jar包 整合

    • struts :2.3.15.3
    • spring : 3.2.0
    • hibernate : 3.6.10

    4.1.1、struts

    • struts-2.3.15.3appsstruts2-blankWEB-INFlib
    • 模板技术,一般用于页面的静态化
      • 1、jsp : *.jsp
      • 2、freemarker :扩展名 :*.ftl
      • 3、velocity :扩展名 :*.vm

    4.1.2、spring

    • 基础 :4 + 1 :beans、core、context、expression + commons-logging (struts中已经导入了)
    • AOP :aop联盟、spring aop 、aspect规范、spring aspect
    • db :jdbc、tx
    • 测试 :test
    • web开发 :spring web
    • 驱动 :mysql
    • 连接池 :c3p0
    • spring整合hibernate :spring orm

    4.1.3、hibernate

    • %h%hibernate3.jar 核心
    • %h%lib equired 必须
    • %h%libjpa jpa规范(java persistent api:java持久api)
      用于hibernate注解开发(注意:Hibernate3中很少用,Hibernate4中推荐使用注解开发),例如:@Entity、@Id 等等。
    • 整合log4j
      • 导入 log4j…jar (struts中已经导入了)
      • 整合(过渡):slf4j-log4j12-1.7.5.jar
    • 二级缓存
    • 核心:ehcache-1.5.0.jar
    • 依赖:
      • backport-util-concurrent-2.1.jar
      • commons-logging (struts中已经导入了)

    4.1.4、整合包

    • spring 整合hibernate :spring orm
    • struts 整合spring :struts2-spring-plugin-2.3.15.3.jar
    • 删除重复jar包:

    4.2、spring整合hibernate:有hibernate.cfg.xml(最熟悉)

    4.2.1、创建表

    create table t_user(
        id int primary key auto_increment,
        username varchar(50),
        password varchar(32),
        age int 
    );

    4.2.2、PO 类(javabean)

    User.java

    package com.itheima.domain;

    public class User {
        /*
         * CREATE TABLE t_user(
              id INT PRIMARY KEY AUTO_INCREMENT,
              username VARCHAR(50),
              PASSWORD VARCHAR(32),
              age INT 
            );
         */
     
        private Integer id;
        private String username;
        private String password;
        private Integer age;

        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
    }

    映射文件User.hbm.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


    <hibernate-mapping>
        <class name="com.itheima.domain.User" table="t_user">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="username"></property>
            <property name="password"></property>
            <property name="age"></property>
        </class>
    </hibernate-mapping>

    pojo类文件和对应的映射文件位置如下:

    4.2.3、dao层

    • spring提供了 HibernateTemplate对象,用于操作PO对象,类似于之前学习Hibernate时的 Session对象。

    UserDao.java

    public interface UserDao {
        /**
         * 保存
         * 
         * @param user
         */

        public void save(User user);
    }

    UserDaoImpl.java

    public class UserDaoImpl implements UserDao {

        // 需要Spring注入模板
        private HibernateTemplate hibernateTemplate;
        public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
            this.hibernateTemplate = hibernateTemplate;
        }

        @Override
        public void save(User user) {
            this.hibernateTemplate.save(user);
        }
    }

    4.2.4、service层

    UserService.java

    public interface UserService {
        /**
         * 注册
         * 
         * @param user
         */

        public void register(User user);
    }

    UserServiceImpl.java

    public class UserServiceImpl implements UserService {

        private UserDao userDao;
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }

        @Override
        public void register(User user) {
            userDao.save(user);
        }
    }

    4.2.5、Hibernate的配置文件 hibernate.cfg.xml

    hibernate.cfg.xml

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">


    <hibernate-configuration>
        <session-factory>
            <!-- 1、基本四项 -->
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql://localhost/day35</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">root</property>

            <!-- 2、配置方言 -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

            <!-- 3、sql语句 -->
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>

            <!-- 4、自动生成表结构(一般没用,因为真正的开发中是先建模,然后通过工具自动生成表结构、SQL语句 等) -->
            <property name="hibernate.hbm2ddl.auto">update</property>

            <!-- 5、本地线程绑定(用处不大,因为事务我们交给Spring管理了) -->
            <property name="hibernate.current_session_context_class">thread</property>

            <!-- 6、导入映射文件 -->
            <mapping resource="com/itheima/domain/User.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>

    4.2.6、Spring的配置文件 applicationContext.xml

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


         <!-- 1、加载hibenrate.cfg.xml,获得 SessionFactory(小结:jdbc开发需要数据源DataSource,hibernate开发需要SessionFactory)
                 * configLocation  确定配置文件位置
         -->

        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
        </bean>

        <!-- 2、先创建模板  
                 * 需要Spring注入模板,该底层使用的就是session,而session是由SessionFactory获得的
        -->

        <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>

        <!-- 3、dao -->
        <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
            <property name="hibernateTemplate" ref="hibernateTemplate"></property>
        </bean>

        <!-- 4、service -->
        <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>

        <!-- 5、事务管理
             5.1、事务管理器 :HibernateTransactionManager 
        -->

        <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>
        <!-- 5.2、事务详情 ,给ABC进行具体的事务设置 -->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="register"/>
            </tx:attributes>
        </tx:advice>
        <!-- 5.3、AOP编程,从 ABCD 业务中 筛选出 ABC -->
        <aop:config>
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
        </aop:config>   

    </beans> 

    4.2.7、测试

    TestApp.java

    package com.itheima;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    import com.itheima.domain.User;
    import com.itheima.service.UserService;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class TestApp {

        @Autowired
        private UserService userService;

        @Test
        public void demo01(){
            User user = new User();
            user.setUsername("bruce");
            user.setPassword("123456");
            user.setAge(26);

            userService.register(user);
        }
    }

    4.3、spring整合hibernate:没有hibernate.cfg.xml【最常用】

    • 删除hibernate.cfg.xml文件,但需要保存文件内容,将其配置到spring中
    • 修改dao层,继承HibernateDaoSupport,spring中删除模板,给dao注入SessionFactory

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

         <!-- 1.1、加载properties文件 -->

         <!-- 1.2、配置数据源 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql:///day35"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>

        <!-- 1.3、配置 LocalSessionFactoryBean,获得SessionFactory 
            * configLocation确定配置文件位置
                <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
            1)dataSource    数据源
            2)hibernateProperties   hibernate其他配置项
            3)导入映射文件
                mappingLocations ,确定映射文件位置,需要加“classpath:”。支持通配符 【常使用】
                    <property name="mappingLocations" value="classpath:com/itheima/domain/User.hbm.xml"></property> 或者
                    <property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property>
                mappingResources ,加载指定的映射文件,默认从src下开始,不需要加“classpath:” 。不支持通配符*
                    <property name="mappingResources" value="com/itheima/domain/User.hbm.xml"></property>
                mappingDirectoryLocations ,加载指定目录下的,所有配置文件
                    <property name="mappingDirectoryLocations" value="classpath:com/itheima/domain/"></property>
                mappingJarLocations ,从jar包中获得映射文件
        -->

        <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>

        <!-- 3、dao spring中删除模板,给dao注入SessionFactory-->
        <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>

        <!-- 4、service -->
        <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>

        <!-- 5 、事务管理
             5.1、 事务管理器 :HibernateTransactionManager 
        -->

        <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>
        <!-- 5.2 、事务详情 ,给ABC进行具体的事务设置 -->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="register"/>
            </tx:attributes>
        </tx:advice>
        <!-- 5.3、AOP编程,从 ABCD 业务中 筛选出 ABC -->
        <aop:config>
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
        </aop:config>   

    </beans> 

    UserDaoImpl.java

    // 底层需要SessionFactory,会自动创建HibernateTemplate模板
    public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

        @Override
        public void save(User user) {
            this.getHibernateTemplate().save(user);
        }
    }

    底层实现详解截图如下:

    4.4、struts整合spring:由spring去创建action

    • 操作步骤如下:
      • 1、编写action类,并将其配置给spring,由spring去创建action,并使spring注入service
      • 2、编写struts.xml
      • 3、编写表单jsp页面
      • 4、web.xml 配置
        • 1、确定Spring xml配置文件位置 contextConfigLocation
        • 2、配置spring 的监听器 ContextLoaderListener
        • 3、配置struts 的前端控制器 StrutsPrepareAndExecuteFilter

    4.4.1、action类

    UserAction.java

    public class UserAction extends ActionSupport implements ModelDriven<User{

        // 1、封装数据
        private User user = new User();

        @Override
        public User getModel() {
            return user;
        }

        // 2、service
        private UserService userService;
        public void setUserService(UserService userService) {
            this.userService = userService;
        }

        /**
         * 注册功能
         * 
         * @return
         */

        public String register() {
            userService.register(user);
            return "success";
        }
    }

    4.4.2、spring配置

    applicationContext.xml

    ......
        <!-- 6、配置action,并配置多例 -->
        <bean id="userAction" class="com.itheima.web.action.UserAction" scope="prototype">
            <property name="userService" ref="userService"></property>
        </bean>
    ......

    4.4.3、struts配置

    struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">


    <struts>
        <!-- 开发模式 -->
        <constant name="struts.devMode" value="true" />

        <package name="default" namespace="/" extends="struts-default">
            <!-- 底层自动从spring容器中通过名称获得内容, getBean("userAction") -->
            <action name="userAction_*" class="userAction" method="{1}">
                <result name="success">/message.jsp</result>
            </action>
        </package>
    </struts>

    4.4.4、jsp表单

    index.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath}/userAction_register" method="post">
            用户名:<input type="text" name="username"/><br/>
            密码:<input type="password" name="password"/><br/>
            年龄:<input type="text" name="age"/><br/>
            <input type="submit" />
        </form> 
    </body>
    </html>

    4.4.5、配置web.xml

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

        id="WebApp_ID" version="2.5">


        <!-- 1、确定Spring 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>
    </web-app>

    4.5、struts整合spring:由struts去创建action【最常用】

    操作步骤如下:

    • 删除spring的action配置
    • struts的< action class="全限定类名">

    struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">


    <struts>
        <!-- 开发模式 -->
        <constant name="struts.devMode" value="true" />

        <package name="default" namespace="/" extends="struts-default">
            <!-- 底层自动从spring容器中通过名称获得内容, getBean("userAction") -->
            <action name="userAction_*" class="com.itheima.web.action.UserAction" method="{1}">
                <result name="success">/message.jsp</result>
            </action>
        </package>
    </struts>
    • 要求:在Action类中,必须提供service名称与spring配置文件一致。(如果名称一致,将自动注入)
    • 1、struts 的配置文件
      • default.properties ,常量配置文件
      • struts-default.xml ,默认核心配置文件
      • struts-plugins.xml ,插件配置文件
      • struts.xml ,自定义核心配置文件
        • 常量的使用时,后面配置项,将覆盖前面的。
    • 2、default.properties ,此配置文件中确定了按照【名称】自动注入,如下图所示:
      • 位置:struts2-core-2.3.15.3.jar/org/apache/struts2/default.properties
    • 3、struts-plugins.xml ,struts整合spring
      • 文件位置:

        打开struts-plugins.xml文件后,有如下一句代码:
        < constant name="struts.objectFactory" value="spring" /> 该配置说明:struts的action将由spring创建

    综上所述:之后的action由spring创建,并按照名称自动注入

    五、练习要求

    • 练习要求截图:
  • 相关阅读:
    android studio无线真机调试------Android
    新建文件夹和文件,并向文件中写入数据---------Android
    wpf获取鼠标的位置-------WPF
    React Native环境搭建
    页面定制CSS代码
    视图优化
    内存优化
    电量优化
    轻量容器、枚举的使用
    AndroidAnnotations框架
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/9446478.html
Copyright © 2020-2023  润新知