Spring (三)

1.1 Spring的事务管理

1.1.1事务

  • 事务:指的是逻辑上一组操作,要么全部成功,要么全部失败。
  • 事务特性:
    • 原子性:事务不可分割。
    • 一致性:事务执行前后,数据完整性保存一致。
    • 隔离性:一个事务执行的时候,不应该受到其他事务的打扰。
    • 持久性:一旦结束,事务就永久保存到数据库。
  • 如果不考虑隔离性,会出现如下问题:
    • 脏读:一个事务读到另一个事务没有提交的数据。
    • 不可重复读:一个事务读取到另一个事务已经提交的事务(update)。
    • 虚读:一个事务读取到另一个事务已经提交的事务(insert)
  • 事务的隔离级别:
    • 未提交读:以上情况都有可能发生。
    • 已提交读:可以避免脏读,但是不可重复读和虚读有可能发生的。
    • 可重复读:可以避免脏读和不可重复读,虚读有可能发生。
    • 串行:可以避免以上的所有情况

1.1.2Spring中的事务管理      

  • 分层开发:事务是处于业务层。
    • Spring提供事务管理API
      • PlatformTransactionManager:平台事务管理器。
        • void commit(TransactionStatus status) throws TransactionException;
        • void rollback(TransactionStatus status) throws TransactionException;
        • TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
      • TransactionDefinitionr:事务定义。
        • ISOLATION_XXX:事务的隔离级别
        • PROPAGATION_XXX:事务的传播行为。(不是JDBC中有的,为了解决实际的开发问题)
        • TIMEOUT_DEFAULT :过期时间.
      • TransactionStatus:事务状态。  

Spring (三)

Spring (三)

Spring (三)

    • 三者之间的关系:PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务.管理事务过程中,产生一些事务状态,事务状态由TransactionStatus记录.
  • API详解:
    • PlatformTransactionManager接口.
      • Spring为不同的持久层框架提供了不同PlatformTransactionManager的实现类.
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring jdbc或MyBaits进行持久化数据的时候使用
org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate3.0版本进行持久化数据的时候使用
org.springframework.orm.jpa.JpaTransactionManager 使用JPA进行持久化时使用
org.springframework.orm.jdo.JdoTransactionManager 当持久化机制是JDO时使用

org.springframework.transaction.jta.JtaTransactionManager

使用给一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用
    • TransactionDefinition接口

事务的隔离级别:

ISOLATION_DEFAULT 默认的,Spring会根据数据库的不同自动切换数据库的隔离级别
ISOLATION_READ_UNCOMMITTED  
ISOLATION_READ_COMMITTED  
ISOLATION_REPEATABLE_READ  
ISOLATION_SERIALIZABLE  

事务的传播行为:(不是jdbc事务管理,用来解决实际开发问题.)传播行为,是用来解决业务层之间的调用的事务的关系.

  • PROPAGATION_REQUIRED:支持当前事务,如果不存在,就创建一个
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A和B是在同一个事务中).
  • PROPAGATION_SUPPORTS:支持当前事务,如果不存在,就不使用事务.
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.
  • PROPAGATION_MANDATORY:支持当前事务,如果不存在,就抛出异常
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常.
  • PROPAGATION_REQUIRES_NEW:如果有事务存在,挂起当前事务,创建一个新的事务.
    • A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中,互不影响).
  • PROPAGATION_NOT_SUPPORTED:以非事务方式云溪行,如果有事务存在,挂起当前事务.
    • A,B 非事务的方式运行,A有事务,就会挂起当前的事务.
  • PROPAGATION_NEVER:以非事务的方式运行,如果事务存在,抛出异常.
  • PROPAGATION_NESTED:如果当前事务存在,则嵌套事务执行.
    • 基于savepoint技术.
    • A.B A有事务,A执行之后,将A事务执行之后的内容保存到savepoint,B事务有异常的话,用户需要自己设置事务提交或回滚.
  • 常用事务传播行为:
    • PROPAGATION_REQUIRED
    • PROPAGATION_REQUIRES_NEW
    • PROPAGATION_NESTED

1.1.3Spring的事务管理

  • Spring的事务管理分为两类:
    • 编程式事务管理:
      • 手动编写代码完成事务管理.  
    • 声明式事务管理:
      • 不需要手动编写代码,配置.

1.1.4事务操作的环境搭建

  • 数据库脚本
CREATE TABLE account (
  id ) NOT NULL AUTO_INCREMENT,
  name ) NOT NULL,
  money double DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE DEFAULT CHARSET=utf8
');
');
');
  • 创建web项目,导入jar包.

Spring (三)

  • 引入配置文件:applicationContext.xml,log4j.properties和jdbc.properties.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- 引入外部属性文件. -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- 配置c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 持久层类 -->
    <bean id="accountDAO" class="cn.spring3.demo1.AccountDAOImpl">
        <!-- 注入连接池对象,通过连接池对象创建模板 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 业务层类 -->
    <bean id="accountService" class="cn.spring3.demo1.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO"/>
    </bean>

</beans>
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=off, stdout 
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring3_day03
jdbc.user=root
jdbc.password=root
  • 创建DAO及Service层的接口以及实现类
package cn.spring3.demo1;

/**
 * Created by love on 2017/5/9.
 */
public interface AccountDAO {
    /**
     * 转出的方法
     * @param from 转出的人
     * @param money 转账金额
     */
    public void out(String from,Double money);

    /**
     * 转入的方法
     * @param to 转入的人
     * @param money 转账金额
     */
    public void in(String to,Double money);

}
package cn.spring3.demo1;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * Created by love on 2017/5/9.
 */
public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {
    @Override
    public void out(String from, Double money) {
        String sql = "update account set money = money - ? where name = ?";
        this.getJdbcTemplate().update(sql,money,from);
    }

    @Override
    public void in(String to, Double money) {
        String sql = "update account set money = money + ? where name = ?";
        this.getJdbcTemplate().update(sql,money,to);
    }
}
package cn.spring3.demo1;

/**
 * Created by love on 2017/5/9.
 */
public interface AccountService {
    /**
     * 转账的方法
     * @param from 转出人
     * @param to 转入人
     * @param money 转账金额
     */
    public void transfer(String from,String to,Double money);

}
package cn.spring3.demo1;

/**
 * Created by love on 2017/5/9.
 */
public class AccountServiceImpl implements AccountService {
    private AccountDAO accountDAO;

    public void setAccountDAO(AccountDAO accountDAO) {
        this.accountDAO = accountDAO;
    }

    @Override
    public void transfer(String from, String to, Double money) {
        accountDAO.out(from,money);
        accountDAO.in(to,money);
    }
}
  • 测试类
package cn.spring3.demo1;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * Created by love on 2017/5/9.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
    @Resource(name="accountService")
    private AccountService accountService;

    @Test
    public void demo1(){
        accountService.transfer("aaa","bbb",100.0);
    }
}

1.1.5Spring的事务管理

  • 手动编码的方式完成事务管理
    • 需要事务管理器:真正管理事务对象.
    • Spring提供了事务管理的模板(工具类).
      • 注册事务管理器:
 <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 需要注入连接池,通过连接池获取连接 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
      • 注册事务模板类
    <!-- 事务管理的模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
      • 在业务层注入模板类(模板类管理事务)
<!-- 业务层类 -->
    <bean id="accountService" class="cn.spring3.demo1.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO"/>
        <!-- 在业务层注入事务管理模板 -->
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
      • 此时的applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- 引入外部属性文件. -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- 配置c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 持久层类 -->
    <bean id="accountDAO" class="cn.spring3.demo1.AccountDAOImpl">
        <!-- 注入连接池对象,通过连接池对象创建模板 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 业务层类 -->
    <bean id="accountService" class="cn.spring3.demo1.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO"/>
        <!-- 在业务层注入事务管理模板 -->
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 需要注入连接池,通过连接池获取连接 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 事务管理的模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

</beans>
      • 在业务层代码上使用模板
package cn.spring3.demo1;

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

/**
 * Created by love on 2017/5/9.
 */
public class AccountServiceImpl implements AccountService {

    private TransactionTemplate transactionTemplate;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    private AccountDAO accountDAO;

    public void setAccountDAO(AccountDAO accountDAO) {
        this.accountDAO = accountDAO;
    }

    @Override
    public void transfer(final String from, final String to, final Double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                accountDAO.out(from,money);

                accountDAO.in(to,money);
            }
        });

    }
}
    • 手动编码方式的缺点:代码量增加,代码有侵入性.
  • 声明式事务管理(原始)
    • 基于TransactionProxyFactoryBean.
      • 注册平台事务管理器.
<!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
      • 创建业务层代理对象
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!-- 注入事务管理器-->
        <property name="transactionManager" ref="transactionManager"/>
        <!-- 目标对象 -->
        <property name="target" ref="accountService"/>
        <!-- 事务的属性设置 -->
        <property name="transactionAttributes">
            <props>
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
      • 编写测试类--注入代理对象
package cn.spring3.demo2;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * Created by love on 2017/5/9.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringTest {
    @Resource(name="accountServiceProxy")
    private AccountService accountService;

    @Test
    public void demo1(){
        accountService.transfer("aaa","bbb",100.0);
    }
}
      • prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
        • 顺序:传播行为,隔离级别,事务是否只读,发生哪些异常可以回滚事务(所有的异常都回滚),发生了哪些异常不回滚.
    • 缺点:就是需要为每一个事务管理的类生成代理,需要为每个类都需要配置.
  • 声明式事务管理(自动代理,基于切面)
    • 引入相应的jar包,如aspectJ等.
    • 引入相应的约束.
<?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">

</beans>
    • 注册事务管理器
<!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    • 定义增强
<!-- 定义增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--  增强(事务)的属性的配置 -->
        <tx:attributes>
            <!--
                isolation:DEFAULT 事务的隔离级别
                propagation:事务的传播行为
                read-only:是否只读
                time-out:是否过期,-1表示不过期
                no-rollback-for:发生哪些异常不回滚
                rollback-for:发生哪些异常回顾
            -->
            <tx:method name="transfer"/>
        </tx:attributes>
    </tx:advice>
    • 定义AOP的配置
<!-- aop配置定义切面和切点的信息-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution( * cn.spring3.demo3.AccountService+.*(..))"/>
        <!--  定义切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
    • 测试类:注入service对象,不需要注入代理对象,因为生成这个类的时候,已经是代理对象.
package cn.spring3.demo3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * Created by love on 2017/5/9.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class SpringTest {
    @Resource(name="accountService")
    private AccountService accountService;

    @Test
    public void demo1(){
        accountService.transfer("aaa","bbb",100.0);
    }
}
  • 基于注解的事务管理
    • 事务管理器
<!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    • 注解事务(开启注解的事务管理)
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    • 在Service上使用注解
      • @Transactional.

Spring (三)

1.2 SSH框架的整合

1.2.1Struts2+Hibernate+Spring导包

  • Struts2导入jar包:
    • Struts2/apps/struts-blank.war/WEB-INF/lib/*.jar
    • 导入与Spring整合的jar包
      • Struts2/lib/struts2-spring-plugin-2.3.15.1.jar  --- 整合Spring框架
      • Struts2/lib/struts2-json-plugin-2.3.15.1.jar  -- 整合AJAX
      • Struts2/lib/struts2-convention-plugin-2.3.15.1.jar  -- 使用Struts2注解开发
    • 配置
      • web.xml文件  
  <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>
      • 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">

    </package>

</struts>
  • Spring导入jar包
    • Spring3.2开发基本的jar包
      • spring-beans-3.2.0.RELEASE.jar
      • spring-context-3.2.0.RELEASE.jar
      • spring-core-3.2.0.RELEASE.jar
      • spring-expression-3.2.0.RELEASE.jar
      • com.springsource.org.apache.commons.logging-1.1.1.jar
      • com.springsource.org.apache.log4j-1.2.15.jar
    • AOP开发
      • spring-aop-3.2.0.RELEASE.jar
      • spring-aspects-3.2.0.RELEASE.jar
      • com.springsource.org.aopalliance-1.0.0.jar
      • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • Spring JDBC开发
      • spring-jdbc-3.2.0.RELEASE.jar

      • spring-tx-3.2.0.RELEASE.jar

    • Spring的事务管理
      • spring-tx-3.2.0.RELEASE.jar

      • Spring整合其他ORM框架
        • spring-orm-3.2.0.RELEASE.jar
      • Spring在web中使用
        • spring-web-3.2.0.RELEASE.jar
      • Spring整合Junit4测试
        • spring-test-3.2.0.RELEASE.jar
    • Spring没有引入c3p0和数据库驱动
    • 配置
      • 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/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"> </beans>
      • log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=info, stdout
    • web.xml中配置监听器
<!-- 配置Spring的监听器 -->
<listener>
    <!-- 监听器默认加载的是WEB-INF/applicationContext.xml -->
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- 指定Spring框架的配置文件所在的位置 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
  • Hibernate导入jar包
    • 核心包:hibernate3.jar
    • lib/required/*.jar
    • lib/jpa/*.har
    • 数据库连接池
    • 数据库驱动
    • slf4j-log4j12-1.7.2.jar
    • 二级缓存
      • ehcache-1.5.0.jar
      • commons-logging.jar
      • backport-util-concurrent.jar
      • ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <!--
    The ehcache-failsafe.xml is a default configuration for ehcache, if an ehcache.xml is not configured.

    The diskStore element is optional. It must be configured if you have overflowToDisk or diskPersistent enabled
    for any cache. If it is not configured, a warning will be issues and java.io.tmpdir will be used.

    diskStore has only one attribute - "path". It is the path to the directory where .data and .index files will be created.

    If the path is a Java System Property it is replaced by its value in the
    running VM.

    The following properties are translated:
    * user.home - User's home directory
    * user.dir - User's current working directory
    * java.io.tmpdir - Default temp file path
    * ehcache.disk.store.dir - A system property you would normally specify on the command line
          e.g. java -Dehcache.disk.store.dir=/u01/myapp/diskdir ...

    Subdirectories can be specified below the property e.g. java.io.tmpdir/one

    -->
    <diskStore path="java.io.tmpdir"/>

    <!--
    Specifies a CacheManagerEventListenerFactory, be used to create a CacheManagerPeerProvider,
    which is notified when Caches are added or removed from the CacheManager.

    The attributes of CacheManagerEventListenerFactory are:
    * class - a fully qualified factory class name
    * properties - comma separated properties having meaning only to the factory.

    Sets the fully qualified class name to be registered as the CacheManager event listener.

    The events include:
    * adding a Cache
    * removing a Cache

    Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility
    of the implementer to safely handle the potential performance and thread safety issues
    depending on what their listener is doing.

    If no class is specified, no listener is created. There is no default.

    <cacheManagerEventListenerFactory class="" properties=""/>
    -->

    <!--
    (Enable for distributed operation)

    Specifies a CacheManagerPeerProviderFactory which will be used to create a
    CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.

    The attributes of cacheManagerPeerProviderFactory are:
    * class - a fully qualified factory class name
    * properties - comma separated properties having meaning only to the factory.

    Ehcache comes with a built-in RMI-based distribution system with two means of discovery of
    CacheManager peers participating in the cluster:
    * automatic, using a multicast group. This one automatically discovers peers and detects
      changes such as peers entering and leaving the group
    * manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
      configuration time.

    Configuring Automatic Discovery:
    Automatic discovery is configured as per the following example:
    <cacheManagerPeerProviderFactory
                        class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
                        properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
                                    multicastGroupPort=4446, timeToLive=32"/>

    Valid properties are:
    * peerDiscovery (mandatory) - specify "automatic"
    * multicastGroupAddress (mandatory) - specify a valid multicast group address
    * multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
      traffic
    * timeToLive - specify a value between 0 and 255 which determines how far the packets will propagate.
      By convention, the restrictions are:
      0   - the same host
      1   - the same subnet
      32  - the same site
      64  - the same region
      128 - the same continent
      255 - unrestricted

    Configuring Manual Discovery:
    Manual discovery is configured as per the following example:
    <cacheManagerPeerProviderFactory class=
                          "net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
                          properties="peerDiscovery=manual,
                          rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
                          | //server1:40000/sampleCache2|//server2:40000/sampleCache2"/>

    Valid properties are:
    * peerDiscovery (mandatory) - specify "manual"
    * rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
                            //hostname:port

    The hostname is the hostname of the remote CacheManager peer. The port is the listening
    port of the RMICacheManagerPeerListener of the remote CacheManager peer.

    <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="peerDiscovery=automatic,
                        multicastGroupAddress=230.0.0.1,
                        multicastGroupPort=4446, timeToLive=1"/>
    -->

    <!--
    (Enable for distributed operation)

    Specifies a CacheManagerPeerListenerFactory which will be used to create a
    CacheManagerPeerListener, which
    listens for messages from cache replicators participating in the cluster.

    The attributes of cacheManagerPeerListenerFactory are:
    class - a fully qualified factory class name
    properties - comma separated properties having meaning only to the factory.

    Ehcache comes with a built-in RMI-based distribution system. The listener component is
    RMICacheManagerPeerListener which is configured using
    RMICacheManagerPeerListenerFactory. It is configured as per the following example:

    <cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName=fully_qualified_hostname_or_ip,
                    port=40001,
                    socketTimeoutMillis=120000"/>

    All properties are optional. They are:
    * hostName - the hostName of the host the listener is running on. Specify
      where the host is multihomed and you want to control the interface over which cluster
      messages are received. Defaults to the host name of the default interface if not
      specified.
    * port - the port the listener listens on. This defaults to a free port if not specified.
    * socketTimeoutMillis - the number of ms client sockets will stay open when sending
      messages to the listener. This should be long enough for the slowest message.
      If not specified it defaults 120000ms.

    <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
    -->

    <!-- Cache configuration.

    The following attributes are required.

    name:
    Sets the name of the cache. This is used to identify the cache. It must be unique.

    maxElementsInMemory:
    Sets the maximum number of objects that will be created in memory

    maxElementsOnDisk:
    Sets the maximum number of objects that will be maintained in the DiskStore
    The default value is zero, meaning unlimited.

    eternal:
    Sets whether elements are eternal. If eternal,  timeouts are ignored and the
    element is never expired.

    overflowToDisk:
    Sets whether elements can overflow to disk when the in-memory cache
    has reached the maxInMemory limit.

    The following attributes are optional.

    timeToIdleSeconds:
    Sets the time to idle for an element before it expires.
    i.e. The maximum amount of time between accesses before an element expires
    Is only used if the element is not eternal.
    Optional attribute. A value of 0 means that an Element can idle for infinity.
    The default value is 0.

    timeToLiveSeconds:
    Sets the time to live for an element before it expires.
    i.e. The maximum time between creation time and when an element expires.
    Is only used if the element is not eternal.
    Optional attribute. A value of 0 means that and Element can live for infinity.
    The default value is 0.

    diskPersistent:
    Whether the disk store persists between restarts of the Virtual Machine.
    The default value is false.

    diskExpiryThreadIntervalSeconds:
    The number of seconds between runs of the disk expiry thread. The default value
    is 120 seconds.

    diskSpoolBufferSizeMB:
    This is the size to allocate the DiskStore for a spool buffer. Writes are made
    to this area and then asynchronously written to disk. The default size is 30MB.
    Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
    lowering this value. To improve DiskStore performance consider increasing it. Trace level
    logging in the DiskStore will show if put back ups are occurring.

    memoryStoreEvictionPolicy:
    Policy would be enforced upon reaching the maxElementsInMemory limit. Default
    policy is Least Recently Used (specified as LRU). Other policies available -
    First In First Out (specified as FIFO) and Less Frequently Used
    (specified as LFU)

    Cache elements can also contain sub elements which take the same format of a factory class
    and properties. Defined sub-elements are:

    * cacheEventListenerFactory - Enables registration of listeners for cache events, such as
      put, remove, update, and expire.

    * bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
      cache on initialisation to prepopulate itself.

    Each cache that will be distributed needs to set a cache event listener which replicates
    messages to the other CacheManager peers. For the built-in RMI implementation this is done
    by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
    distributed cache's configuration as per the following example:

    <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
         properties="replicateAsynchronously=true,
         replicatePuts=true,
         replicateUpdates=true,
         replicateUpdatesViaCopy=true,
         replicateRemovals=true "/>

    The RMICacheReplicatorFactory recognises the following properties:

    * replicatePuts=true|false - whether new elements placed in a cache are
      replicated to others. Defaults to true.

    * replicateUpdates=true|false - whether new elements which override an
      element already existing with the same key are replicated. Defaults to true.

    * replicateRemovals=true - whether element removals are replicated. Defaults to true.

    * replicateAsynchronously=true | false - whether replications are
      asynchronous (true) or synchronous (false). Defaults to true.

    * replicateUpdatesViaCopy=true | false - whether the new elements are
      copied to other caches (true), or whether a remove message is sent. Defaults to true.

    * asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
      replicator runs at a set interval of milliseconds. The default is 1000. The minimum
      is 10. This property is only applicable if replicateAsynchronously=true

    The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
    used. It is configured as per the following example:

    <bootstrapCacheLoaderFactory
        class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
        properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"/>

    The RMIBootstrapCacheLoaderFactory recognises the following optional properties:

    * bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
      after the cache has started. If false, bootstrapping must complete before the cache is
      made available. The default value is true.

    * maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
      memory limits of the VM. This property allows the bootstraper to fetched elements in
      chunks. The default chunk size is 5000000 (5MB).

    -->

    <!--
    Mandatory Default Cache configuration. These settings will be applied to caches
    created programmtically using CacheManager.add(String cacheName)
    -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>
    • 配置Hibernate的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>
    <!-- 必须去配置的属性 -->
    <!-- 配置数据库连接的基本信息: -->
    <property name="hibernate.connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="hibernate.connection.url">
        jdbc:mysql:///ssh1
    </property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">123</property>
    <!-- Hibernate的方言 -->
    <!-- 生成底层SQL不同的 -->
    <property name="hibernate.dialect">
        org.hibernate.dialect.MySQLDialect
    </property>

    <!-- 可选的属性 -->
    <!-- 显示SQL -->
    <property name="hibernate.show_sql">true</property>
    <!-- 格式化SQL -->
    <property name="hibernate.format_sql">true</property>

    <property name="hibernate.connection.autocommit">false</property>
    <!-- hbm:映射 to DDL: create drop alter -->
    <property name="hibernate.hbm2ddl.auto">update</property>

    <!-- C3P0连接池设定-->
    <!-- 使用c3po连接池  配置连接池提供的供应商-->
    <property name="connection.provider_class">
        org.hibernate.connection.C3P0ConnectionProvider
    </property>

    <!--在连接池中可用的数据库连接的最少数目 -->
    <property name="c3p0.min_size">5</property>
    <!--在连接池中所有数据库连接的最大数目  -->
    <property name="c3p0.max_size">20</property>
    <!--设定数据库连接的过期时间,以秒为单位,
        如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
    <property name="c3p0.timeout">120</property>
    <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
    <property name="c3p0.idle_test_period">3000</property>

    <!-- 通知Hibernate加载那些映射文件 -->
    <mapping resource="" />

</session-factory>
</hibernate-configuration>
      • 映射:类名.hbm.xml

1.2.2Struts2和Spring的整合

  • 新建包结构
    • cn.vo
    • cn.dao
    • cn.service
    • cn.action
  • 新建实体类
package cn.vo;

public class Book {
    private Integer id;
    private String name;
    private Double price;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }

}
  • 新建一个jsp页面--addBook.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <title>My JSP 'addBook.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
    <h1>添加图书</h1>
    <s:form action="book_add" namespace="/" method="post" theme="simple">
        图书名称:<s:textfield name="name" /><br/>
        图书价格:<s:textfield name="price" /><br/>
        <s:submit value="添加"/>
    </s:form>
  </body>
</html>
  • 创建Action
package cn.action;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

import cn.vo.Book;

public class BookAction extends ActionSupport implements ModelDriven<Book> {
    private Book book = new Book();

    @Override
    public Book getModel() {

        return book;
    }

    public String add(){
        System.out.println("web层的添加方法");
        return Action.NONE;
    }

}
  • 配置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">
        <action name="book_*" class="cn.action.BookAction" method="{1}">

        </action>

    </package>

</struts>

1.2.3Struts2和Spring的整合两种方式

  • Struts2自己管理Action(一) ---Struts2框架自动创建Action的类
<action name="book_*" class="cn.action.BookAction" method="{1}"> </action>
  • Action交给Spring管理(二):
    • 可以在<action>标签上通过一个伪类名的方式进行配置,如下代码所示的class="bookAction"
  <package name="default" namespace="/" extends="struts-default">
        <action name="book_*" class="bookAction" method="{1}">

        </action>

    </package>
    • 在Spring的配置文件中,如下代码所示,但是此时的id="bookAction"需要上面配置的class="bookAction"中相同.
<?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">

    <!-- 配置Action -->
    <bean id="bookAction"  class="cn.action.BookAction" scope="prototype"></bean>

    <!-- Service的配置 -->
    <bean id="bookService" class="cn.service.BookService"></bean>
    <!-- DAO的配置 -->
    <bean id="bookDAO" class="cn.dao.BookDAO"></bean>

</beans>
    • [注意]:Action交给Spring管理一定要配置scope="prototype".
    • 推荐使用方式二,在Spring中管理的类,可以对其进行AOP开发,统一的管理.
  • web层获取Service
    • 传统方式:
      • 获得WebApplicationConext对象
      • 通过WebApplicationConext中的getBean("")
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getRequest().getServletContext());
BookService bookService = (BookService) applicationContext.getBean("bookService");
    • 实际开发:
      • 引入了struts2-spring-plugin-2.3.15.1.jar
      • 有一个配置文件struts-plugin.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--
/*
 * $Id: struts-plugin.xml 1221225 2011-12-20 12:22:28Z jogep $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
-->
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />

    <!--  Make the Spring object factory the automatic default -->
    <constant name="struts.objectFactory" value="spring" />

    <constant name="struts.class.reloading.watchList" value="" />
    <constant name="struts.class.reloading.acceptClasses" value="" />
    <constant name="struts.class.reloading.reloadConfig" value="false" />

    <package name="spring-default">
        <interceptors>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
        </interceptors>
    </package>
</struts>
      • 开启常量:<constant name="struts.objectFactory" value="spring" />
      • 引发另一个常量(Spring的工厂类按照名称自动注入):struts.objectFactory.spring.autoWire = name
package cn.action;

import org.apache.struts2.ServletActionContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

import cn.service.BookService;
import cn.vo.Book;

public class BookAction extends ActionSupport implements ModelDriven<Book> {
    private BookService bookService;

    public void setBookService(BookService bookService) {
        this.bookService = bookService;
    }

    private Book book = new Book();

    @Override
    public Book getModel() {

        return book;
    }

    public String add(){
        System.out.println("Action层增加图书");
        bookService.add(book);
        return Action.NONE;
    }

}

1.2.4Spring和Hibernate的整合

  • Spring整合Hibernate框架的时候有两种方式:
  • 零障碍整合(一):可以在Spring中引入Hibernate的配置文件
    • 通过LocalSessionFactoryBean在Spring中直接hibernate.cfg.xml
    <!-- 零障碍整合 在Spring配置文件中引入Hibernate的配置文件 -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
    </bean>
    • Spring提供了Hibernate的模板,只需要将HibernateTemplate模板注入给DAO.
package cn.dao;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.vo.Book;

public class BookDAO extends HibernateDaoSupport{

    public void add(Book book) {
        this.getHibernateTemplate().save(book);

    }

}
  <!-- DAO的配置 -->
    <bean id="bookDAO" class="cn.dao.BookDAO">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    • 创建Book.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="cn.vo.Book" table="book" >
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name"/>
        <property name="price" column="price"/>
    </class>
</hibernate-mapping>
    • 事务管理器
<!-- 管理事务 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    • 注解管理事务
<tx:annotation-driven transaction-manager="transactionManager"/>
    • 在业务层类上添加一个注解
package cn.service;

import org.springframework.transaction.annotation.Transactional;

import cn.dao.BookDAO;
import cn.vo.Book;
@Transactional
public class BookService {
    private BookDAO bookDAO;

    public void setBookDAO(BookDAO bookDAO) {
        this.bookDAO = bookDAO;
    }

    public  void add(Book book) {
        bookDAO.add(book);
        System.out.println("业务层增加图书");

    }

}  
上一篇:Python函数参数详解


下一篇:io多路复用的精髓