目录:
1、回顾事务2、spring事务管理
3、事务案例--转账
4、手动管理事务(了解)
5、工厂bean 生成代理:半自动(了解)
6、AOP配置事务--基于xml【掌握】
7、AOP配置事务--基于注解【掌握】
8、整合web--在web.xml中配置spring容器
9、从Servlet中获取spring容器
10、SSH整合--jar包
11、spring整合hibernate:没有hibernate.cfg.xml 【重点】
12、spring整合struts:struts创建action 【重点】
1、回顾事务 <--返回目录
* 事务:一组业务操作ABCD,要么全部成功,要么全部不成功。
* 特性:ACID
- 原子性:整体
- 一致性:完成
- 隔离性:并发
- 持久性:结果
* 隔离问题:
- 脏读:一个事务读到另一个事务没有提交的数据
- 不可重复读:一个事务读到另一个事务已提交的数据(update)
- 虚读(幻读):一个事务读到另一个事务已提交的数据(insert)
* 隔离级别:
- read uncommitted:读未提交。存在3个问题
- read committed:读已提交。解决脏读,存在2个问题
- repeatable read:可重复读。解决:脏读、不可重复读,存在1个问题。
- serializable :串行化。都解决,单事务。
* mysql 事务操作
ABCD 一个事务
Connection conn = null;
try{
//1 获得连接
conn = ...;
//2 开启事务
conn.setAutoCommit(false);
A
B
C
D
//3 提交事务
conn.commit();
} catche(){
//4 回滚事务
conn.rollback();
}
* mysql 事务操作--Savepoint
需求:AB(必须),CD(可选)
Connection conn = null;
Savepoint savepoint = null; //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)
try{
//1 获得连接
conn = ...;
//2 开启事务
conn.setAutoCommit(false);
A
B
savepoint = conn.setSavepoint();
C
D
//3 提交事务
conn.commit();
} catche(){
if(savepoint != null){ //CD异常
// 回滚到CD之前
conn.rollback(savepoint);
// 提交AB
conn.commit();
} else{ //AB异常
// 回滚AB
conn.rollback();
}
}
2、spring事务管理 <--返回目录
* 涉及事务,首先需要jar包:spring-tx-3.2.0.RELEASE.jar
* 三个顶级接口
- PlatformTransactionManager 平台事务管理器,spring要管理事务,必须使用事务管理器
进行事务配置时,必须配置事务管理器。
- TransactionDefinition:事务详情(事务定义、事务属性),spring用于确定事务具体详情,
例如:隔离级别、是否只读、超时时间 等
进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。
- TransactionStatus:事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
spring底层根据状态进行相应操作。
* 以后,我们需要做的:配置事务管理器,配置事务详情,事务状态我们不管
* 常见的事务管理器
- DataSourceTransactionManager,jdbc开发时事务管理器,采用JdbcTemplate
** 需要导spring-jdbc-3.2.0.RELEASE.jar
- HibernateTransactionManager,hibernate开发时事务管理器,整合hibernate
** 需要导spring-orm-3.2.0.RELEASE.jar
* 事务管理器的api详解
TransactionStatus getTransaction(TransactionDefinition definition):事务管理器 通过"事务详情",
获得"事务状态",从而管理事务。
void commit(TransactionStatus status) 根据状态提交
void rollback(TransactionStatus status) 根据状态回滚
* 事务状态TransactionStatus的方法
isNewTranction():是否是新的事务
hasSavepoint():是否有保存点
setRollbackOnly():设置回滚
isRollbackOnly():是否回滚
flush():刷新
isCompleted():是否完成
* 事务详情TransactionDefinition
- getName()方法:配置事务详情名称,一般取方法名称,例如save、add*等
- isReadOnly():是否只读,一般增删改:读写,查询:只读
- getTimeout():获得超时时间
- getIsolationLevel():隔离级别
- getPropagationBehavior():传播行为
- TIMEOUT_DEFAULT:默认超时时间,默认值-1,使用数据库底层的超时时间
- ISOLATION_DEFAULT:隔离级别 0 1 2 4 8
- ISOLATION_READ_UNCOMMITTED
- ISOLATION_READ_COMMITTED
- ISOLATION_REPEATABLE_READ
- ISOLATION_SERIALIZABLE
- 传播行为:在两个业务之间如何共享事务 A调用B,设置B的传播行为
** PROPAGATION_REQUIRED【默认值】 required 必须:支持当前事务,A有事务,B将使用该事务;
如果A没有事务,B将创建一个新的事务
** PROPAGATION_SUPPORTS supports 支持:支持当前事务,A有事务,B将使用该事务;
如果A没有事务,B将以非事务执行
** PROPAGATION_MANDATORY mandatory 强制:支持当前事务,A有事务,B将使用该事务;
如果A没有事务,B将抛异常
** PROPAGATION_REQUIRES_NEW【以后常用】 必须新的:如果A有事务,将A的事务挂起,
B创建一个新的事务;如果A没有事务,B创建新的事务
** PROPAGATION_NOT_SUPPORTED 不支持:如果A有事务,将A的事务挂起,B将以非事务执行;
如果A没有事务,B将以非事务执行
** PROPAGATION_NEVER 不支持事务,也不支持当前事务:如果A有事务,B将抛异常;
如果A没有事务,B以非事务执行
** PROPAGATION_NESTED【也要掌握】 嵌套:A和B底层采用保存点机制,执行嵌套事务
3、事务案例--转账 <--返回目录
创建表
create database db_test1 default character set utf8;
use db_test1;
create table t_account(
id int primary key auto_increment,
username varchar(50),
money int
)engine innodb;
insert into t_account(username,money) values('jack','1000');
insert into t_account(username,money) values('rose','1000');
导入jar包
** 核心:4+1
** aop :4 (aop联盟、spring aop、aspectjweaver规范、spring aspect)
** jdbc和事务相关:2(jdbc、tx)
** 驱动:mysql
** 连接池:c3p0
dao层:接口和实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void out(String outer, Integer money) {
this.getJdbcTemplate().update("update account set money = money - ?
where username = ?", money,outer);
}
@Override
public void in(String inner, Integer money) {
this.getJdbcTemplate().update("update account set money = money + ?
where username = ?", money,inner);
}
}
service层:接口和实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money); //outer减钱
//断电,这样就会导致:outer减钱,但是inter不加钱
//int i = 1/0;
accountDao.in(inner, money); //inter加钱
}
}
spring配置
<!-- 1 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- 2 dao 依赖JdbcTemplate,继承JdbcDaoSupport,需要注入数据源
-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3 service 依赖dao层,需要注入accountDao-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
测试
@Test
public void demo01(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean
("accountService");
accountService.transfer("jack", "rose", 100);
}
4、手动管理事务(了解) <--返回目录
* spring底层使用TransactionTemplate事务模板进行操作
* 操作
- service需要获得TransactionTemplate
- 所以,在spring配置TransactionTemplate,并注入到service
- 模板TransactionTemplate需要注入事务管理器
- 所以,需要配置事务管理器DataSourceTransactionManager
- 事务管理器需要注入DataSource
1) 配置数据源
2) 配置事务管理器(依赖数据源)
3) 配置模板TransactionTemplate(依赖事务管理器)
4) 配置service(依赖模板TransactionTemplate)
5、工厂bean 生成代理:半自动(了解) <--返回目录
spring提供了管理事务的代理工厂bean TransactionProxyFactoryBean
1) spring 配置一个代理<bean id="" class="TransactionProxyFactoryBean"/>
2) getBean(TransactionProxyFactoryBean的id值)获得代理对象
spring配置文件:
<!-- 4 service 代理对象
4.1 proxyInterfaces 接口
4.2 target 目标类
4.3 transactionManager 事务管理器
4.4 transactionAttributes 事务属性(事务详情)
prop.key :确定哪些方法使用当前事务配置
prop.text:用于配置事务详情
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
传播行为 隔离级别 是否只读 异常回滚 异常提交
注意:如果这里配置readOnly只读,若执行增删改,会报错
+Exception:表示有异常,仍提交。可能导致,事务只执行一部分业务
例如:
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默认传播行为,
和隔离级别
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只读
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.
ArithmeticException</prop> 有异常仍提交
-->
<bean id="proxyAccountService" class="org.springframework.transaction.interceptor.
TransactionProxyFactoryBean">
<property name="proxyInterfaces" value="com.itheima.service.AccountService"></property>指定接口
<property name="target" ref="accountService"></property> 【指定一个目标类】
<property name="transactionManager" ref="txManager"></property> 指定事务管理器
<property name="transactionAttributes"> 指定事务详情
<props>
<!-- 指定目标类的transfer()方法使用当前事务配置 -->
<prop key="【目标类方法】transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
</props>
</property>
</bean>
<!-- 5 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
6、AOP配置事务--基于xml【掌握】 <--返回目录
在spring xml 配置aop 自动生成代理,进行事务的管理,三步
1)配置管理器
2)配置事务详情
3)配置aop
<!-- 4 事务管理 -->
<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 4.2 事务详情(事务通知) , 在aop筛选基础上,对ABC三个确定使用什么样的事务。例如:AC读写、B只读 等
<tx:attributes> 用于配置事务详情(属性属性)
<tx:method name=""/> 详情具体配置
propagation 传播行为 , REQUIRED:必须;REQUIRES_NEW:必须是新的
isolation 隔离级别
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 4.3 AOP编程,目标类有ABCD(4个连接点),切入点表达式 确定增强的连接点,从而获得切入点:ABC -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
</aop:config>
7、AOP配置事务--基于注解【掌握】 <--返回目录
步骤:
1)配置事务管理器,将并事务管理器交予spring
2)在目标类或目标方法添加注解即可
** 在目标类上配,则作用整个类;在目标方法上配,则作用于该方法
** @Transactional
** @Transactional(propagation=Propagation.REQUIRED , isolation = Isolation.DEFAULT)
在applicationContext.xml中配置
<!-- 4 事务管理 -->
<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 4.2 将管理器交予spring
* transaction-manager 配置事务管理器
* proxy-target-class true:底层强制使用cglib 代理
-->
<tx:annotation-driven transaction-manager="txManager"/>
8、整合web--在web.xml中配置spring容器 <--返回目录
* 以前测试都是new出spring容器,例如:
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("jack", "rose", 1000);
* 但是spring容器创建一次就够了
* 导入jar包 spring-web
* 所以,为了让spring配置文件在服务器第一次启动就加载,在web.xml中配置
<!-- 确定spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置spring监听器,加载xml配置文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
9、从Servlet中获取spring容器 <--返回目录
* 在Servlet中获取spring容器,从而可以使用
- Spring把WebApplicationContext(XmlWebApplicationContext是默认实现类)放在了ServletContext中,
ServletContext也是一个“容器”,也是一个类似Map的结构,而WebApplicationContext在ServletContext中
的KEY就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
我们如果要使用WebApplicationContext则需要从ServletContext取出,Spring提供了一个
WebApplicationContextUtils类,可以方便的取出WebApplicationContext,
只要把ServletContext传入就可以了。
---------------------
方法一:
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
ac.getBean("beanId");
说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。
方法二:通过Spring提供的工具类获取ApplicationContext对象
ApplicationContext ac1 = WebApplicationContextUtils
.getRequiredWebApplicationContext(ServletContext sc);
ApplicationContext ac2 = WebApplicationContextUtils
.getWebApplicationContext(ServletContext sc);
ac1.getBean("beanId");
ac2.getBean("beanId");
说明:这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,
然后在通过它获取需要的类实例。
上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。
其中 servletContext sc 可以具体 换成 servlet.getServletContext()或者 this.getServletContext()
或者 request.getSession().getServletContext(); 另外,由于spring是注入的对象放在
ServletContext中的,所以可以直接在ServletContext取出 WebApplicationContext 对象:
WebApplicationContext webApplicationContext = (WebApplicationContext)servletContext
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
---------------------
【总结:通过ServletContext对象获取Spring容器】
//方式1
ApplicationContext applicationContext=(ApplicationContext)this.getServletContext()
.getAtt·ribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
//方式2
ApplicationContext applicationContext=WebApplicationContextUtils
.getWebApplicationContext(this.getServletContext());
//然后在Servlet中可以使用spring容器--applicationContext了
10、SSH整合--jar包 <--返回目录
最好新建一个文件夹,然后往里面添加jar包,然后添加到项目里
struts2:2.3.15.3
hibernate : 3.6.10
spring: 3.2.0
* jar包整合
- struts2:共13个
- spring
** 核心 4+1:beans、core、context、expression,commons-logging (struts已经导入)
** aop相关 4个:aop联盟、spring-aop 、aspect规范、spring-aspect
** 数据库db 2个:spring-jdbc、spring-tx
** 整合jUnit:spring-test
** 整合web:spring-web
** 整合hibernate:spring-orm
** 驱动:mysql
** 连接池:c3p0
共4+4+2+5=15
- hibernate
** 核心 1个:hibernate3.jar
** 必须:6个
** jpa规范 1个
** 整合log4j
导入 log4j...jar (struts已经导入)
整合(过渡):slf4j-log4j12-1.7.5.jar
** 二级缓存
核心:ehcache-1.5.0.jar
依赖:backport-util-concurrent-2.1.jar和commons-logging(存在)
共8+1+2=11
- spring整合hibernate: spring-orm前面写了
struts整合spring:struts2-spring-plugin-2.3.15.3.jar
- 所以,整合ssh共:13+15+11+1=40个 删除一个重复的javassist,最终39个
11、spring整合hibernate:没有hibernate.cfg.xml 【重点】 <--返回目录
* 与使用jdbcTemplate类似
* dao层,继承HibernateDaoSupport
// 底层需要SessionFactory,自动创建HibernateTemplate模板
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void save(User user) {
this.getHibernateTemplate().save(user);
}
}
* 使用c3p0数据源,数据源4大参数存放到properties文件中
新建jdbcinfo.properties文件,添加一些内容
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8
jdbc.user=root
jdbc.password=
* applicationContext.xml文件配置
<!-- 1.1 加载properties文件 -->
<context:property-placeholder location="classpath:com/itheima/f_properties/jdbcInfo.properties"/>
<!-- 1.2 配置数据源 -->
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 1.3 配置 LocalSessionFactoryBean,获得 ->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
<property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property>
</bean>
<!-- 2 dao,需要注入sessionFactory -->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 3 service -->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
12、spring整合struts:struts创建action 【重点】 <--返回目录
配置web.xml
<!-- 1 确定applicationContext.xml位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 2 spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 3 struts 前端控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
要求:Action类中,必须提供service名称与spring配置文件中<bean id="">的id一致。(如果名称一样,将自动注入)