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:事务状态。
- PlatformTransactionManager:平台事务管理器。
- 三者之间的关系:PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务.管理事务过程中,产生一些事务状态,事务状态由TransactionStatus记录.
- API详解:
- PlatformTransactionManager接口.
- Spring为不同的持久层框架提供了不同PlatformTransactionManager的实现类.
- 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包.
- 引入配置文件: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.
- 注册平台事务管理器.
- 基于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
- 顺序:传播行为,隔离级别,事务是否只读,发生哪些异常可以回滚事务(所有的异常都回滚),发生了哪些异常不回滚.
- 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.
- 在Service上使用注解
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
- Spring3.2开发基本的jar包
- Spring的事务管理
spring-tx-3.2.0.RELEASE.jar
- Spring的事务管理
- 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
- Spring整合其他ORM框架
- <?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
- 配置Hibernate的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("业务层增加图书"); } }