Spring概述:
什么是Spring?
spring(由Rod Johnson创建的一个开源框架)spring是一个开源框架,由Rod Johnson创建,简单来说,spring是一个分层的javaSE/EEfull-stack(一站式)轻量级框架。
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson在其著作Expert One-On-One J2EEDevelopment and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
EE开发分成三层结构:
WEB层:spring mvc
业务层:Bean管理(IOC)
持久层:spring的jdbc模板,ORM模板用于整合其他的持久层框架
Expert One-to-One J2EE Design andDevelopment :J2EE的设计和开发:(2002.EJB)
Expert One-to-One J2EE Development withoutEJB :J2EE不使用EJB的开发.
为什么学习Spring
方便解耦,简化开发
Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
Spring IOC
IOC底层实现原理:
IOC:Inversion ofControl 控制反转. 指的是 对象的创建权反转(交给)给Spring.
作用是实现了程序的解耦合.
Spring的入门案例:
步骤一:官网http://spring.io/
下载地址:http://repo.springsource.org/libs-release-local/org/springframework/sprin解压:(Spring目录结构:)
* docs :API和开发规范.
* libs :jar包和源码.
* schema :约束.
步骤二:创建web项目,引入spring的开发包
引入的jar包:
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
spring-beans-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar
步骤三:引入相关配置文件:
log4j.properties
applicationContext.xml
引入约束:
spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
步骤四:编写相关的类
public interface UserDao {
public void sayHello();
}
public class UserDaoImpl implements UserDao {
@Override
public void sayHello() {
System.out.println("Hello Spring...");
}
}
步骤五:完成配置:
<bean id="userDao" class="cn.itcast.spring.demo1.UserDaoImpl"></bean>
步骤六:编写测试程序:
@Test
// Spring的方式:
public void demo2(){
// 创建Spring的工厂类:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂解析XML获取Bean的实例.
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.sayHello();
}
IOC:
控制反转,将对象的创建权交给了spring
DI:
Dependency Injection 依赖注入需要有IOC的环境,spring创建这个类的过程中,spring将类的依赖的属性设置进去
spring中的工厂:
applicationContext:
ClassPathXmlApplicationContext ---加载路径下的spring的配置文件
FileSystemXmlApplicationContext ---加载本地磁盘下的spring配置文件
BeanFactory:
BeanFactory 和applicationContext区别:
BeanFactory: 实在getBean的时候才会生成的实例
ApplicationContext: 在加载appliactionContext.xml时就会创建
配置STShe的xml信息:
点击add
spring的相关配置:
id属性和name属性标签的配置:
id :Bean起个名字. 在约束中采用ID的约束:唯一. 必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 id:不能出现特殊字符.
<bean id=”bookAction”>
name:Bean起个名字. 没有采用ID的约束. name:出现特殊字符.如果<bean>没有id的话 , name可以当做id使用.
* 整合struts1的时候:
<bean name=”/loginAction” >
scope属性:Bean的范围:
* singleton :默认值,单例的.
* prototype :多例的.
* request :WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中.
* session :WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中.
* globalSession :WEB项目中,应用在Porlet环境.如果没有Porlet环境那么globalSession相当于session.
Bean的生命周期的配置:通过配置<bean>标签上的init-method作为Bean的初始化的时候执行的方法,配置destroy-method作为Bean的销毁的时候执行的方法。
销毁方法想要执行,需要是单例创建的Bean而且在工厂关闭的时候,Bean才会被销毁.
spring的bean管理xml的方式
spring的bean的属性注入:
<!-- 第一种:构造方法的方式 -->
<bean id="car" class="cn.itcast.spring.demo4.Car">
<constructor-arg name="name" value="保时捷"/>
<constructor-arg name="price" value="1000000"/>
</bean>
<!-- 第二种:set方法的方式 -->
<bean id="car2" class="cn.itcast.spring.demo4.Car2">
<property name="name" value="奇瑞QQ"/>
<property name="price" value="40000"/>
</bean>
spring的属性注入:对象类型的注入:
<!-- 注入对象类型的属性 -->
<bean id="person" class="cn.itcast.spring.demo4.Person">
<property name="name" value="会希"/>
<!-- ref属性:引用另一个bean的id或name -->
<property name="car2" ref="car2"/>
</bean>
名称空间p的属性注入的方式:
Spring2.x版本后提供的方式.
第一步:引入p名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
第二步:使用p名称空间.
* 普通属性: p:属性名称=””
* 对象类型属性: p:属性名称-ref=””
<!-- p名称空间的属性注入的方式 -->
<bean id="car2" class="cn.itcast.spring.demo4.Car2" p:name="宝马7" p:price="1200000"/>
<bean id="person" class="cn.itcast.spring.demo4.Person" p:name="思聪" p:car2-ref="car2"/>
SpEL的方式的属性注入:
Spring3.x版本后提供的方式
SpEL:Spring Expression Language.
语法:#{ SpEL }
<!-- SpEL的注入的方式 -->
<bean id="car2" class="cn.itcast.spring.demo4.Car2">
<property name="name" value="#{'奔驰'}"/>
<property name="price" value="#{800000}"/>
</bean>
<bean id="person" class="cn.itcast.spring.demo4.Person">
<property name="name" value="#{'冠希'}"/>
<property name="car2" value="#{car2}"/>
</bean>
<bean id="carInfo" class="cn.itcast.spring.demo4.CarInfo"></bean>
引用了另一个类的属性
<bean id="car2" class="cn.itcast.spring.demo4.Car2">
<!-- <property name="name" value="#{'奔驰'}"/> -->
<property name="name" value="#{carInfo.carName}"/>
<property name="price" value="#{carInfo.calculatePrice()}"/></bean>
注入复杂类型:
<!-- Spring的复杂类型的注入===================== -->
<bean id="collectionBean" class="cn.itcast.spring.demo5.CollectionBean">
<!-- 数组类型的属性 -->
<property name="arrs">
<list>
<value>会希</value>
<value>冠希</value>
<value>天一</value>
</list>
</property>
<!-- 注入List集合的数据 -->
<property name="list">
<list>
<value>芙蓉</value>
<value>如花</value>
<value>凤姐</value>
</list>
</property>
<!-- 注入Map集合 -->
<property name="map">
<map>
<entry key="aaa" value="111"/>
<entry key="bbb" value="222"/>
<entry key="ccc" value="333"/>
</map>
</property>
<!-- Properties的注入 -->
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>
spring的分配置文件的开发:
一种:创建工厂的时候加载多个配置文件:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
二种:在一个配置文件中包含另一个配置文件:
<import resource="applicationContext2.xml"></import>
spring的bean管理(注解方式)
注解开发实例
步骤一:下载spring开发包
步骤二:创建web项目,引入sprng的开发包
步骤三:引入相关配置
log4j.properties
applicationContext.xml
引入约束:
spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html
* 引入约束:(引入context的约束):
<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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
步骤五:编写相关类:
public interface UserDao {
public void sayHello();
}
public class UserDaoImpl implements UserDao {
@Override
public void sayHello() {
System.out.println("Hello Spring...");
}
}
步骤六:配置注解扫描
<!-- Spring的注解开发:组件扫描(类上注解: 可以直接使用属性注入的注解) -->
<context:component-scan base-package="com.itheima.spring.demo1"/>
在相关类上添加注解:
@Component(value="userDao")
public class UserDaoImpl implements UserDao {
@Override
public void sayHello() {
System.out.println("Hello Spring Annotation...");
}
}
编写测试类:
@Test
public void demo2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.sayHello();
}
spring的bean管理中常用的注解:
作用在类上:
@Component ---作用在类上
@Controller ----web层
@service ---业务层
@Repository ---持久层
controller、service\repository是@component的衍生注解(功能目前来讲是一样的)
这三个注解是为了让标注类本身的用途清晰,spring在后续的版本会对其增强
属性注入的注解
(使用注解注入的方式,可以不提供set方法)
@Value :用于注入普通类型.
@Autowired :自动装配:
* 默认按类型进行装配.
* 按名称注入:
* @Qualifier:强制使用名称注入.
@Resource相当于:
* @Autowired和@Qualifier一起使用.
bean的作用域范围:
@Scope:
* singleton:单例
* prototype:多例
bean的生命周期的配置:
@PostConstruct :相当于init-method
@PreDestroy :相当于destroy-method
spring的bean管理的方式的比较:
xml和注解:
xml:结构清晰
注解:开发方便
实际开发过程中海油一种xml和注解整合开发
bean有xml配置,但是使用的属性使用注解注入。
AOP(面向切面编程)
AOP概述:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现功能的统一维护的一种技术。AOP是oop的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Spring是解决实际开发中的一些问题
AOP解决oop中遇到的一些问题,是oop的延续。
为什么学习AOP:
对程序进行增强:不修改源码的情况下.
* AOP可以进行权限校验,日志记录,性能监控,事务控制.
AOP由来:
AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范.
底层实现:
代理机制:
* Spring的AOP的底层用到两种代理机制:
* JDK的动态代理 :针对实现了接口的类产生代理.
* Cglib的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类的子类对象.
JDK动态代理增强一个类中的方法:
public class MyJDKProxy implements InvocationHandler {
private UserDao userDao;
public MyJDKProxy(UserDao userDao) {
this.userDao = userDao;
}
// 编写工具方法:生成代理:
public UserDao createProxy(){
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(), this);
return userDaoProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
System.out.println("权限校验================");
}
return method.invoke(userDao, args);
}
}
cglib动态代理增强一个类中的方法:
public class MyCglibProxy implements MethodInterceptor{
private CustomerDao customerDao;
public MyCglibProxy(CustomerDao customerDao){
this.customerDao = customerDao;
}
// 生成代理的方法:
public CustomerDao createProxy(){
// 创建Cglib的核心类:
Enhancer enhancer = new Enhancer();
// 设置父类:
enhancer.setSuperclass(CustomerDao.class);
// 设置回调:
enhancer.setCallback(this);
// 生成代理:
CustomerDao customerDaoProxy = (CustomerDao) enhancer.create();
return customerDaoProxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("delete".equals(method.getName())){
Object obj = methodProxy.invokeSuper(proxy, args);
System.out.println("日志记录================");
return obj;
}
return methodProxy.invokeSuper(proxy, args);
}
}
Spring基于AspectJ的AOP开发
AOP开发中的相关术语:
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.
spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合
Spring使用AspectJ进行AOP开发(xml方式)
步骤一:引入相关的jar包:
* spring的传统AOP的开发的包
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
* aspectJ的开发包:
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
引入AOP约束:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
</beans>
编写目标类:
创建接口和类:
public interface OrderDao {
public void save();
public void update();
public void delete();
public void find();
}
public class OrderDaoImpl implements OrderDao {
@Override
public void save() {
System.out.println("保存订单...");
}
@Override
public void update() {
System.out.println("修改订单...");
}
@Override
public void delete() {
System.out.println("删除订单...");
}
@Override
public void find() {
System.out.println("查询订单...");
}
}
目标类配置:
<!-- 目标类================ -->
<bean id="orderDao" class="cn.itcast.spring.demo3.OrderDaoImpl">
</bean>
整合junit单元测试:
引入spring-test.jar
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
@Resource(name="orderDao")
private OrderDao orderDao;
@Test
public void demo1(){
orderDao.save();
orderDao.update();
orderDao.delete();
orderDao.find();
}
}
通知类型:
前置通知 :在目标方法执行之前执行. 后置通知 :在目标方法执行之后执行 环绕通知 :在目标方法执行前和执行后执行 异常抛出通知:在目标方法执行出现 异常的时候 执行 最终通知 :无论目标方法是否出现异常 最终通知都会 执行. |
切入点表达式:
execution(表达式) 表达式: [方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数) public * cn.itcast.spring.dao.*.*(..) * cn.itcast.spring.dao.*.*(..) * cn.itcast.spring.dao.UserDao+.*(..) * cn.itcast.spring.dao..*.*(..) |
public class MyAspectXml {
// 前置增强
public void before(){
System.out.println("前置增强===========");
}
}
配置完成增强:
<!-- 配置切面类 -->
<bean id="myAspectXml" class="cn.itcast.spring.demo3.MyAspectXml"></bean>
<!-- 进行aop的配置 -->
<aop:config>
<!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.OrderDao.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<aop:before method="before" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
其他的配置增强:
<!-- 配置切面类 -->
<bean id="myAspectXml" class="cn.itcast.spring.demo3.MyAspectXml"></bean>
<!-- 进行aop的配置 -->
<aop:config>
<!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.*Dao.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.*Dao.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.*Dao.update(..))" id="pointcut3"/>
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.*Dao.find(..))" id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<aop:before method="before" pointcut-ref="pointcut1"/>
<aop:after-returning method="afterReturing" pointcut-ref="pointcut2"/>
<aop:around method="around" pointcut-ref="pointcut3"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4"/>
<aop:after method="after" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
使用spring的AOP对客户管理的DAO进行增强(注解)
案例:
对于CRM的系统而言,现在有很多的DAO类,比如客户的DAO,联系人DAO等等。客户提出一个需求要开发人员实现一个功能对所有的DAO的类中以save开头的方法实现权限的校验,需要时管理员的身份才可以进行保存操作。
步骤一:引入相关的jar包
同xml方式开发的jar包包括aop的开发包和aspectJ的开发包
步骤二:引入spring配置文件
引入AOP约束:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
</beans>
步骤三:编写测试类:
public class ProductDao {
public void save(){
System.out.println("保存商品...");
}
public void update(){
System.out.println("修改商品...");
}
public void delete(){
System.out.println("删除商品...");
}
public void find(){
System.out.println("查询商品...");
}
}
配置目标类:
<!-- 目标类============ -->
<bean id="productDao" class="cn.itcast.spring.demo4.ProductDao"></bean>
开启aop注解的自动代理
<aop:aspectj-autoproxy/>
AspectJ的aop注解:
@Aspect:定义切面类的注解
通知类型: * @Before :前置通知 *@AfterReturing :后置通知 * @Around :环绕通知 * @After :最终通知 *@AfterThrowing :异常抛出通知.
@Pointcut:定义切入点的注解 |
@Aspect
public class MyAspectAnno {
@Before("MyAspectAnno.pointcut1()")
public void before(){
System.out.println("前置通知===========");
}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.save(..))")
private void pointcut1(){}
}
配置切面:
<!-- 配置切面类 -->
<bean id="myAspectAnno" class="cn.itcast.spring.demo4.MyAspectAnno"></bean>
其他通知的注解
@Aspect
public class MyAspectAnno {
@Before("MyAspectAnno.pointcut1()")
public void before(){
System.out.println("前置通知===========");
}
@AfterReturning("MyAspectAnno.pointcut2()")
public void afterReturning(){
System.out.println("后置通知===========");
}
@Around("MyAspectAnno.pointcut3()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前通知==========");
Object obj = joinPoint.proceed();
System.out.println("环绕后通知==========");
return obj;
}
@AfterThrowing("MyAspectAnno.pointcut4()")
public void afterThrowing(){
System.out.println("异常抛出通知========");
}
@After("MyAspectAnno.pointcut4()")
public void after(){
System.out.println("最终通知==========");
}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.save(..))")
private void pointcut1(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.update(..))")
private void pointcut2(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.delete(..))")
private void pointcut3(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.find(..))")
private void pointcut4(){}
}
spring事物管理完成转账的案例
相关知识点:
spring的JDBC的模板:
spring提供了很多持久层技术的模板类简化编程:
传统jdbc开发
创建数据库和表
引入相关的开发包:
spring的基本的开发包6个
mysql-connector-java-5.1.7-bin.jar
spring-jdbc-4.2.4.RELEASE.jar
spring-tx-4.2.4.RELEASE.jar
创建一个测试类:
@Test
// JDBC模板的基本使用:
public void demo1(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring_day03");
dataSource.setUsername("root");
dataSource.setPassword("123");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("insert into account values (null,?,?)", "会希",10000d);
}
将连接池的配置交给spring管理:
spring内置的连接池的配置:
引入spring的配置文件
配置内置的连接池:
<!-- 配置Spring的内置连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring_day02"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
将模板配置到spring中
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
编写测试类:
**** 引入spring-aop.jar
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void demo1(){
jdbcTemplate.update("insert into account values (null,?,?)", "凤姐",10000d);
}
}
spring中配置dbcp连接池:
导入jdbc连接池的jar包
com.springsource.org.apache.commons.dbcp-1.2.2.osgil.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
连接池配置
<!-- 配置DBCP连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring_day02"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
配置c3p0连接池:
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
配置连接池:
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///spring_day02"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
</bean>
JDBC模板的CRUD的操作:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
// 插入操作
public void demo1(){
jdbcTemplate.update("insert into account values (null,?,?)", "冠希",10000d);
}
@Test
// 修改操作
public void demo2(){
jdbcTemplate.update("update account set name=?,money =? where id = ?", "思雨",10000d,5);
}
@Test
// 删除操作
public void demo3(){
jdbcTemplate.update("delete from account where id = ?", 5);
}
@Test
// 查询一条记录
public void demo4(){
Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 1);
System.out.println(account);
}
@Test
// 查询所有记录
public void demo5(){
List<Account> list = jdbcTemplate.query("select * from account", new MyRowMapper());
for (Account account : list) {
System.out.println(account);
}
}
class MyRowMapper implements RowMapper<Account>{
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
return account;
}
}
}
事务的回顾:
什么是事物:
事务逻辑上的一组操作,组成这个组操作的各个逻辑单元,要么一起成功,要么一起失败。
事务的特性:
原子性:强调事务的不可分割
一致性:事务的执行的前后数据的完整性保持一致
隔离性:一个事务执行过程中,不应该受到其他事物的干扰
持久性:事务一旦结束,数据库就持久到数据库
如果不考虑隔离性引发的安全性的问题:
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读 :一个事务读到了另一个事务已经提交的update的数据导致多次查询结果不一致.
虚读 :一个事务读到了另一个事务已经提交的insert的数据导致多次查询结果不一致.
解决读问题:设置事务隔离级别
未提交读 :脏读,不可重复读,虚读都有可能发生
已提交读 :避免脏读。但是不可重复读和虚读有可能发生
可重复读 :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 :避免以上所有读问题.
spring进行事务管理一组的API
PlatformTransactionManager:平台事务管理器
***** 真正管理事务的对象 org.springframework.jdbc.datasource.DataSourceTransactionManager使用Spring JDBC或iBatis 进行持久化数据时使用 org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate版本进行持久化数据时使用 |
事务定义信息;
隔离级别
传播行为
超时信息
是否只读
TransactionStatus:事务的状态
记录事务的状态
spring的这组接口是如何进行事务管理的
平台事务管理根据事务定义的信息进行事务的管理,事务管理的过程中产生一些状态,将这些状态记录到TransactionStatus里面
事务的传播行为:
PROPAGION_XXX :事务的传播行为 * 保证同一个事务中 PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认) PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务 PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
* 保证没有在同一个事务中 PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务 PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务 PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行 |
案例代码:
创建业务层和DAO的类:
public interface AccountService {
public void transfer(String from,String to,Double money);
}
public class AccountServiceImpl implements AccountService {
// 业务层注入DAO:
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
/**
* from:转出的账号
* to:转入的账号
* money:转账金额
*/
public void transfer(String from, String to, Double money) {
accountDao.outMoney(from, money);
accountDao.inMoney(to, money);
}
}
public interface AccountDao {
public void outMoney(String from,Double money);
public void inMoney(String to,Double money);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money,from);
}
@Override
public void inMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,to);
}
}
配置业务层和DAO
<!-- 配置业务层的类 -->
<bean id="accountService" class="cn.itcast.transaction.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 配置DAO的类 -->
<bean id="accountDao" class="cn.itcast.transaction.demo1.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
编写测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringDemo4 {
@Resource(name="accountService")
private AccountService accountService;
@Test
// 转账的测试:
public void demo1(){
accountService.transfer("会希", "凤姐", 1000d);
}
}
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.itcast.transaction.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<!-- 注入事务管理模板 -->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
手动编写代码实现事务管理
public void transfer(final String from, final String to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.outMoney(from, money);
int d = 1 / 0;
accountDao.inMoney(to, money);
}
});
}
spring的声明式事务管理xml方式(*******):思想就是AOP
不需要手动编写代码,通过一段配置完成事务管理
引入aop的包:
spring-aop.jar
aspectJ.jar
spring-aspects.jar
恢复转账环境
配置事务管理器
<!-- 事务管理器 -->
<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="REQUIRED" 传播行为
read-only="false" 只读
timeout="-1" 过期时间
rollback-for="" -Exception
no-rollback-for="" +Exception
-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
配置aop:
<aop:config>
<aop:pointcut expression="execution(* cn.itcast.transaction.demo2.AccountServiceImpl.transfer(..))" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
spring的声明式注解方式:(****)
引入的jar包
com.springsource.org.aopalliance-1.0.0.jar
com.springspurce.org.aspectj.weaver-1.6.8.REALEASE.jar
spring-aop-4.2.4.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
spring-jdbc-4.2.4.RELEASE.jar
Spring-tx-4.2.4.RELEASE.jar
恢复转账环境
配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
开启事务管理的注解
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>