第一章
1.Spring采用4种策略降低Java开发复杂度
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
使用POJO名称是为了避免和EJB混淆起来, 而且简称比较直接. 其中有一些属性及其getter setter方法的类,没有业务逻辑,有时可以作为VO(value -object)或dto(Data Transform Object)来使用.当然,如果你有一个简单的运算属性也是可以的,但不允许有业务方法,也不能携带有connection之类的方法。
2.依赖注入的三种方式
1. 接口注入
2. Setter方法注入
3. 构造方法注入
具体可参考:http://developer.51cto.com/art/201106/266978.htm
依赖注入:让组件依赖于抽象,当组件要与其他实际对象发生依赖关系时,通过抽象来注入依赖的实际对象。 最大的好处是松耦合。
3.Spring最常用的三种应用上下文
1)ClassPathXmlApplicationContext:从classpath处获取xml文件来加载一个上下文。
2)ClassPathXmlApplicationContext:从文件系统中获取xml文件来加载一个上下文。
3)XmlWebApplicationContext:从web应用获取xml文件来加载一个上下文。
这三个类都是ApplicationContext接口的实现。
使用:
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");//config.xml在src目录下
ApplicationContext context = new FileSystemXmlApplicationContext("d:/config.xml");
4.Bean的生命周期
第二章
1.两种配置bean的方法
2.factory-method
3.bean的作用域
singleton | 在每个Spring IoC容器中一个bean定义对应一个对象实例。 |
prototype | 一个bean定义对应多个对象实例,每次调用都创建一个实例 |
request | 在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring |
session | 在一个HTTP |
global session | 在一个全局的HTTP |
4.initi-method和destroy-method
第三章
1.自动装配与自动检测
自动装配:让spring自动识别如何装配bean的依赖关系,减少对<property>元素的使用。
自动检测:让spring自动识别哪些类需要配置成spring Bean,减少对<bean>元素的使用。
2.4种类型的自动装配
1.byName:寻找和属性名相同的bean,若找不到,则装不上。
2.byType:寻找和属性类型相同的bean,找不到,装不上,找到多个抛异常。
3.constructor:查找和bean的构造参数一致的一个或多个bean,若找不到或找到多个,抛异常。按照参数的类型装配
4.autodetect: 首先尝试constructor进行自动装配,然后再尝试byType.
<bean id="bar" class="Bar" autowire="byName"/>
3.@Autowired和@Inject
@Autowired有required属性,@Inject没有,所以inject注解所标注的依赖关系必须存在,如果不存在就抛出异常
4.自动检测与过滤条件
例如:
<context:component-scan>
<context:include-filter type=”assigable”expression=”com.springinaction.springidol.Instrument”/>
</context:component-scan>
type与expression的联合使用使继承Instrument的类注册为Spring bean。
5.限定依赖
@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。
第四章
1.AOP的术语
2.通过XML配置切面
这个可以随便找个例子,很好理解<aop:config> 5 <!-- 6 切入点表达式 7 --> 8 <aop:pointcut expression="execution(* cn.itcast.spring.aop.sh.PersonDaoImpl.*(..))" id="perform"/> 9 <aop:aspect ref="myTransaction"> 10 <!-- 11 <aop:before method="beginTransaction" pointcut-ref="perform"/> 12 <aop:after-returning method="commit" pointcut-ref="perform" returning="var"/> 13 --> 14 <aop:after method="finallyMethod" pointcut-ref="perform"/> 15 <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/> 16 <aop:around method="aroundMethod" pointcut-ref="perform"/> 17 </aop:aspect> 18 </aop:config>
3.注解切面
@Component("myTransaction") 26 @Aspect 27 public class MyTransaction extends HibernateUtils{ 28 private Transaction transaction; 29 30 @Pointcut("execution(* cn.itcast.spring.aop.annotation.sh.PersonDaoImpl.*(..))") 31 private void aa(){}//方法签名 返回值必须是void 方法的修饰符最好是private ,aa是随便定义的 做类比 32 33 @Before("aa()") 34 public void beginTransaction(JoinPoint joinpoint){ 35 this.transaction = sessionFactory.getCurrentSession().beginTransaction(); 36 } 37 38 @AfterReturning(value="aa()",returning="val") 39 public void commit(Object val){ 40 this.transaction.commit(); 41 }
第五章
1.可能抛出SQLException的常见问题
1)应用程序无法连接数据库
2)查询语法粗偶
3)查询中使用的表或列不存在
4)视图插入或更新的数据违反了数据库的完整性约束
2.ORM的一些特性
1)延迟加载
比如我们要查询一组PurchaseOrder对象,每个对象都包含一个LineItem对象所形成的集合。如果只关心PurchaseOrder对象,那么可以延迟加载lineitem对象。但是会把一次查询分解成多次。
2)预先抓取
与延迟加载相对。预先抓取可以在一个操作中一起提取出lineitem对象,节省多次查询的成本。
3)级联
更改数据库的表会同时修改其他表。
3. @repository注解
在类上使用这个注解,会为我们做两件事。首先,会被自动检测到,不必声明bean。另外,如果在Spring配置文件中声明了PersistenceExceptionTranslationPostProcessor,它会给所有@repository注解的类上加一个通知器(advisor),这样就会捕获所有平台相关的异常并且以Spring的非检查型数据访问异常的形式重新抛出。
第六章
可以参考http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/
对Spring事务有详细讲解
1.事务的4个特性
ACID
原子性(atomic):事务中的所有操作要么全部发生要不全部不发生。其中任意一个活动失败,整个事务也失败并且回滚。
一致性(Consistent):一旦事务完成,系统必须确保它所建模的业务处于一致的状态。
隔离性(Isolated): 并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。在事务并发操作时,可能出现的问题有:
脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。
事务的隔离级别从低到高有:
Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
通常,在工程实践中,为了性能的考虑会对隔离性进行折中。
持久性(Durability)
事务提交后,对系统的影响是永久的。一般涉及到把结果存储到数据库或其他形式的持久化存储中。
2.Spring与事务
3.编码式事务
可以方便的使用模板
public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionTemplate transactionTemplate; ...... public boolean transfer(final Long fromId, final Long toId, final double amount) { return (Boolean) transactionTemplate.execute(new TransactionCallback(){ public Object doInTransaction(TransactionStatus status) { Object result; try { result = bankDao.transfer(fromId, toId, amount); } catch (Exception e) { status.setRollbackOnly(); result = false; System.out.println("Transfer Error!"); } return result; } }); } }
4.声明式事务
基于 @Transactional 的声明式事务管理
除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如清单12所示:
清单12. 基于 @Transactional 的事务管理示例配置文件
@Transactional(propagation = Propagation.REQUIRED) public boolean transfer(Long fromId, Long toId, double amount) { return bankDao.transfer(fromId, toId, amount); }
Spring 使用 BeanPostProcessor 来处理 Bean 中的标注,因此我们需要在配置文件中作如下声明来激活该后处理 Bean,如清单13所示:
清单13. 启用后处理Bean的配置
<tx:annotation-driven transaction-manager="transactionManager"/>
声明式事务通过事务属性来定义,事务属性描述了事务策略如何应用到方法上。
事务隔离级别
上文有事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
事务的只读属性
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
事务的回滚规则
通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。