spring是什么?
spring是分层的一站式轻量级开源框架,为表现层,持久层,业务层,AOP,事务控制等提供解决方案,占用资源不多,使用方便
spring的核心是IoC和AOP,即控制反转和面向切面的编程
IoC是指将对象创建权力交给spring工厂进行管理强调的是由spring创建对象这件事,DI强调的是spring工厂创建对象时将该对象的依赖对象一并创建出来
AOP基于动态代理功能增强,在不修改源代码的情况下对功能的拓展
spring的好处
1.方便解耦,简化开发
2.AOP编程
3.声明事务的支持
4.方便程序测试,集成了junit单元测试
5.方便继承各种优秀的框架
6.降低javaee API的使用难度
使用注解的步骤:
引入依赖,引入xml约束头,开启注解扫描包
常用注解:
@Component
@Controller
@Service
@Repository
@Autowired
@Resource
@Aspect
@Before
@After
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
</beans>
什么是AOP
在不修改源代码的情况下,对目标方法进行增强
共有代码抽取出来,放置到某个地方集中管理,具体运行时再由容器动态织入这些共有的代码
1.程序员在编写具体业务逻辑时,只需要关心核心的业务逻辑处理,既提高了工作效率,又让代码简洁优雅
2.日后维护中由于业务逻辑代码与共有代码分开存放,而且共有代码是集中存放的,因此使维护工作变得简单轻松
aop相关术语:
连接点:有可能被拦截的点,spring中指的是方法,
切入点:通过配置文件确定被拦截的方法,
通知/增强:拦截之后要增强逻辑代码,分为前置通知,后置通知,异常通知,最终通知,环绕通知
切面:是切入点和增强的结合
AOP编程的两种方式:
1.传统编程,非常复杂不再使用;
2.AspectJ框架下编程,spring2.0之后推荐使用
现在的AOP编程都是通过AOP框架(AspectJ)实现
@Before 前置通知
@AfterReturning 后置通知
@Around 环绕通知
@AfterThrowing 抛出通知
@After 最终通知
AOP 流程
1.编写目标,切入点
2.编写通知,增强的方法
3.导包和引入约束
4.配置aop自动代理
5.配置切入点和切面
注意:
1.增强以及目标都是由spring管理的;
2.声明切面类@Aspect ,配置切入点表达式是在切面类中进行配置,一般情况下就是增强的类
2.使用切入点表达式进行配置
//切入点表达式的两种形式
@Before(value = "bean(userController)")
@Before("execution(* org.kgc..*(..))")
execution(* cn.ly.service..*.*(..))
aop应用场景:
记录日志;
监控方法的运行时间(监控性能);
权限控制;
缓存优化(第一次查询数据库将查询结果放入缓存,第二次调用,直接从缓存中命中并返回);
事务管理(调用方法前先开启事务,调用方法后提交关闭事务);
spring整合mybatis
核心思想是将sqlsession 和 sqlsessionfactory 交给 spring 来管理,spring将配置文件也当作bean对象来处理
jar包的选择:如果使用mybatis3.4版本以上可以使用mybatis-spring-1.3以上的版本
如果使用mybatis3.4一下的版本,可以使用mybatis-spring-1.3以下的版本
导入配置文件,spring,mybatis,log4j,db.properties,
编写配置文件,思想是将mybatis的相关内容都交给spring管理
1.将数据源文件交给spring管理:spring中提供了PropertyPlaceholderConfigurer来进行管理,将数据源文件进行注入;
注意,有location的,一般都会加classpath: 表示在src下
2.spring接管数据源,使用数据库连接池,dbcp使用BasicDataSource,c3p0使用ComboPooledDataSource,druid使用DruidDataSource
3.将mybatis工厂交给spring管理,spring提供了sqlsessionfactorybean来管理,他需要依赖数据源的信息
注意:1.在工厂中还可以使用configLocation引入mybatis配置
2.使用mapperLocation引入映射器,在value中需要添加classpath
3.使用typeAliasesPackage进行别名扫描
将sqlsession对象交给spring管理,spring提供了sqlsessiontemplate来管理sqlsession
将接口也交给spring来管理,使用mapperscannerconfigurer进行管理
spring事务管理
事务管理的四大特性:
ACID:
原子性:事务的整个操作是一个整体,不可分割,要么成功要么失败
一致性:事务操作的前后,涉及该事务的整体数据没有变化
隔离性:事务操作是相互隔离不受影响的
持久性:事务结束数据一旦提交,将永久改变表中数据
事务管理操作:
开启事务管理,开启之后sql语句并不会马上执行并把结果写入表中,而是会写入事务日志中,start transaction
回滚操作,会清掉开始事务之后写到事务日志中的内容,即恢复到开启事务之前,roolback
注意:回滚操作只是回退增删改的内容,对于查询语句不能回退
事务提交:commit,持久化保存
spring的事务管理由三个接口共同完成:
PlatformTransactionMannager 事务管理器
TransactionDefinition 事务定义信息(通过配置如何进行事务管理:隔离,传播,超时,只读)
TransactionStatus 事务状态(事务管理过程中,每个时间点事务状态信息)
DataSourceTransactionManager针对JdbcTemplate MyBatis事务控制,使用Connection进行事务控制
开启事务, conn.setAutoCommit(false);
提交事务,conn.commit();
回滚事务,conn.roolback();
HibernateTransactionManager针对Hibernate框架进行事务管理,使用session的Transaction相关操作进行事务控制
开启事务, session.beginTransaction();
提交事务,session.getTransaction().commit();
回滚事务,session.getTransaction().roolback();
用户应该选择和使用持久层技术对应的事务管理器
事务的隔离级别:
default 使用后端数据库默认的隔离级别
READ_UNCOMMITTED 允许读取还没提交的数据,可能导致脏读,幻读,不可重复读
READ_COMMITTED 允许在并发事务已经提交后读取,可防止脏读,但仍然可能幻读,不可重复读(Oracle级别)
REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变.可防止脏读,不可重复读,但幻读仍然可能发生.(MySQL级别)
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读幻读和不可重复读.这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中设计的数据表来完成的
脏读:一个事务读取了另一个事务还没提交的数据,一旦这个数据被回滚的读取的是无效数据.
幻读:一个事务读取了几行数据后另一个事务插入一些记录,幻读就发生了,再后来的查询中第一个事务就会发现有些原来没有的记录
不可重复读:同一事务中,多次读取同一数据返回的结果不同,也就是后续读取能读到另一事务已经提交的更新数据.可重复读指的是后续读取不能读到另一事务已经提交的数据
事务传播的行为:
用于解决两个被事务管理的方法互相调用的问题
面试题:
REQUIERD/REQUIRES_NEW/NESTED区分
REQUIRED:支持当前事务,A调用B,如果A存在,AB处于同一事务
REQUIRES_NEW :不会支持原来的事务,A调用B,A存在的话,B肯定不会和A处于同一事务
NESTED:嵌套事务,只对DataSourceTransactionManager有效,底层使用jdbc的SavePoint机制,允许同一事务设置保存点,回滚到保存点
事务的结束必须通过commit,
try{
操作
commit;
}catch(){
roolback;
}
spring支持两种管理事务的方式
1.编程式要修改原来的代码,加入事务管理代码,会带来事务侵入,不推荐使用
实际中是通过TransactionTemplate操作事务管理
template.execute(new TransactionCallbackWithoutResult(){
void doInTransactionWithoutResult(TransactionStatus status){
需要管理事务的代码
}
})
2.声明式事务管理:底层就是AOP环绕通知,使用注解接口实现,推荐使用
步骤:
1.引入aop和tx的名称空间,导入aop和tx的jar
2.配置transactionManager
根据不同的持久层框架,配置不同的事务管理器,事务管理器需要依赖数据源信息
3.配置切入点和切面
注解配合方式添加事务管理@Transactional
第一步,配置注解驱动事务管理,
第二步,在需要管理事务的方法或者类上面添加@Transactional注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 将包下对象交给spring管理-->
<context:component-scan base-package="cn.ly"/>
<!-- 启动aop的自动代理-->
<aop:aspectj-autoproxy/>
<!--开启spring对事务管理的注解驱动,否则识别不了注解 -->
<tx:annotation-driven/>
<!-- 引入数据库连接文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">-->
<!-- <property name="location" value="log4j.properties"/>-->
<!-- </bean>-->
<!-- 配置数据库连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${data.driver}"/>
<property name="url" value="${data.url}"/>
<property name="username" value="${data.username}"/>
<property name="password" value="${data.password}"/>
</bean>
<!-- 配置工厂,将工厂对象交给spring管理-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 依赖数据源-->
<property name="dataSource" ref="dataSource"/>
<!-- mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 加载包下所有映射文件-->
<property name="mapperLocations" value="classpath:cn/ly/mapperxml/*.xml"/>
<!-- 将包下的实体类设置别名,和mybatisX兼容性差-->
<!-- <property name="typeAliasesPackage" value="com.kgc.pojo"/>-->
</bean>
<!-- sqlSession对象交给spring管理-->
<bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sessionFactory"/>
</bean>
<!-- 将接口也交给spring进行管理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 定义接口扫描包-->
<property name="basePackage" value="cn.ly.mapper"/>
</bean>
<!--添加spring对事务管理的支持-->
<!-- 1.事务管理器
2.通知,切入点
3.切面
注解方式只需要配置事务管理器
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- <tx:advice id="txAdvice">-->
<!-- <tx:attributes>-->
<!-- <tx:method name="transfer"/>-->
<!-- </tx:attributes>-->
<!-- </tx:advice>-->
<!-- <aop:config>-->
<!-- <aop:pointcut id="pointCut" expression="execution(* cn.ly.service..*.*(..))"/>-->
<!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>-->
<!-- </aop:config>-->
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--开启驼峰映射规则-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 类型别名-->
<typeAliases>
<package name="cn.ly.pojo"/>
</typeAliases>
</configuration>
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
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
log4j.rootLogger=info, stdout