赞
踩
Spring是一个引擎,是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就是控制翻转(IOC),和面向切面(AOP),简单的说就是一个分层的轻量级开源框架。
Spring原理和组成:Spring为简化我们的开发工作,封装了一系列的开箱即用的组件功能模块,包括:Spring JDBC 、Spring MVC 、Spring Security、 Spring AOP 、Spring ORM 、Spring Test等。
理念(目的):解决企业应用开发的复杂性,使现有的技术更加容易使用,本身是一个大杂烩整合了现有的框架。
优点:
1、Spring是一个免费开源的框架(容器)!
2、Spring是一个轻量级的非入侵的框架!
3、控制反转(IOC),面向切面编程(AOP)
4、支持事务的处理,对框架整合的支持!
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!
Spring包含了SpringMVC,而SpringBoot又包含了Spring或者说是在Spring的基础上做得一个扩展。
spring mvc < spring < springboot
Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便。
SSM框架:Spring+SpringMVC+MyBatis
Spring MVC:属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
MyBatis: 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
Rod Johnson:Spring Framework的创始人,音乐学的博士学位,轮子理论:就是不要重复发明轮子
框架可以类比如造房子的框架和造桥梁的框架,类库可以类比如为钢材,类库更加通用。
软件系统日趋复杂
重用度高,开发效率和质量高
软件设计人员要专注于对领域的了解,使需求更充分易于上手、快速解决问题。
面向接口编程的例子:
接口:
实现类:
调用:
什么是IOC?
依赖:ClassA中使用ClassB的属性或者方法,叫做ClassA依赖于ClassB
每一行是一个单独的框架,所做的工作是不同的
主要学习Spring Framework
1、轻量,Spring框架使用的Jar都比较小,一般在1M以下或者几百kb,Spring核心功能所需的jar总共在3M左右。
2、针对接口编程,解耦合,Spring提供了IOC控制反转。由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成,对象之间依赖解耦合。
3、AOP编程的支持,通过提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付,在Spring中,开发人员可以从繁杂的事物管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4、方便集成各种优秀的框架,spring不排斥各种优秀的开源框架,相反Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架等的直接支持。简化框架的使用,Spring像插线板一样,其他框架是插头,可以容易的组合到一起。需要使用哪个框架就把这个插头放入插线板。不需要可因轻易移除。
Spring由20多个模块组成,他们可以分为数据访问/集成、web、面向切面编程(AOP、Aspects)、集成功能模块(JVM代理(instrumentation)、消息返送(Messaging))、核心容器(Core Container)和测试(Test)。
IOC:控制反转,是一个理论,概念,思想。
描述:把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是在其他外部资源完成
控制:创建对象,对象的属性赋值对象之间关系管理。
反转:把原来的开发管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象。创建对象,给属性赋值。
正转:由开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象。
容器:是一个服务器软件,一个框架(Spring)
为什么要使用IOC:目的是减少对代码的改动,也能实现不同的功能,实现解耦合。
java中创建对象有哪些方式:
Spring是使用的DI实现了IOC的功能,spring底层创建对象,使用的是反射机制。
Spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。
步骤:
使用maven骨架quickstart来创建一个maven项目
修改pom.xml文件
正传:(测试代码)
创建Spring配置文件
在resource文件中创建spring配置文件beans.xml文件
创建容器,使用容器来创建对象, ApplicationContext就是表示spring容器,通过容器获取对象
从容器中获取某个对象,调用对象的方法,getBean(“配置文件中的id值”);
对象是在执行语句时所创建的:
ApplicationContext appCon = new ClassPathXmlApplicationContext(config);
创建对象的时间是:在创建Spring的容器时,它会创建配置文件中所有的对象。
spring创建对象:默认调用的是无参构造方法
1、在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
2、使用spring中的注解,完成属性赋值,叫做基于注解的di实现
1、set注入(设值注入):spring调用类的set方法,在set方法可以实现属性的赋值。
大部分使用set注入
实现步骤:
1)创建maven项目
2)加入maven的依赖,spring的依赖,版本5.2.5版本,junit依赖
3)创建类(接口和他的实现类)
和没有使用框架一样,就是普通的类。
4)创建spring需要使用的配置文件
声明类的信息,这些类由spring创建和管理
通过spring的语法,完成属性的赋值
5)测试属性的创建。
注入:就是赋值的意思
简单类型:spring中规定java的基本数据类型和string都是简单类型。
1)简单类型的set注入
一个property只能给一个属性赋值
set注入调用了set方法:
设值注入的注意事项:
1、如果类中没有set方法,就会报错,说明如果类没有set方法不可以set注入。
2、set注入首先是调用类的无参构造方法创建对象
3、set注入只要有set方法就可以注入,和创建的属性无关,set注入只是使用set方法
2)引用类型的设置注入
引用类型的set注入:spring调用类的set方法
<bean id="类对象的取一个名称" class="类的路径"> <property name="属性名称l" ref="bean的id(对象的名称)"></property> </bean>
- 1
- 2
- 3
2、构造注入,spring调用类的有参数构造方法,创建对象,在构造方法中完成赋值。
构造注入使用标签
标签:一个表示构造方法的一个参数
标签属性:
name:表示构造方法的参数的位置,参数从左往右位置是0,1,2的顺序
value:构造方法的形参类型是简单类型,使用value
ref:构造方法的形参类型是引用类型,使用ref
使用name属性实现构造方法注入:(先后顺序可以变)
使用index属性实现注入:(先后顺序可以变)
使用非自定义的类进行构造注入:
单元测试:
main方法测试的话不方便,每个方法单独测试就使用单元测试
使用单元测试:
1、需要在pom.xml文件中加入junit依赖
junit
junit
4.11
test
2、创建测试用的类:叫做测试类
src/test/java目录中创建类
3、创建测试方法
1)public方法
2)没有返回值void
3)方法名称自定义、建议名称是test+你要测试方法的名称
4)方法没有参数
5)方法的上面加入@Test,这样的方法是可以单独执行的。不用使用main方法。
引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值。不用自己再给引用类型赋值了
使用的规则常用的是byName,byType.
1、byName(按照名称注入):java类中引用类型的属性名和spring容器中(配置文件的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
语法:
简单类型属性赋值
定义student类:三个set方法,两个简单类型一个引用类型
spring配置文件:在student对象中申明autowire属性,赋值byName,对简单类型进行赋值,引用对象的id设置为类中引用属性的属性名
java类中引用类型的数据类型和spring容器中(配置文件)的class属性是同源关系的,这样bean能够赋值给引用类型
同源就是一类的意思:
1、java类引用类型的数据类型和bean的class的值是一样的。
2、java类中引用类型的数据类型和bean的class的值父子类关系的。
3、java类中引用类型的数据类型和bean的class值接口和实现类关系的
语法:
简单类型属性赋值
注意:在byType中,在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的。
实际开发中使用多个配置文件
优势是:
1、每个文件的大小比一个文件要小很多,效率高
2、避免多人竞争带来冲突。(多个模块相关功能在一起)
如果你的项目有多个模块(相关的功能在一起),一个模块一个配置文件。
学生考勤模块,一个配置文件, 张三
学生成绩一个配置文件, 李四
多文件的分配方式:
1、按照功能的模块,一个模块一个配置文件
2、按类的功能,数据库相关的配置一个配置文件,做事务的功能的一个配置文件,做service功能的一个配置文件
包含关系的配置文件:
spring-total表示配置文件:包含其他的配置文件,主配置文件一般是不定义对象的。
语法:
关键字:“classpath:”表示类路劲(class文件所在的目录),
在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉spring到哪去加载读取
例如:(在包含关系的配置文件中,可以使用通配符如:*表示任意字符)
注意:主的配置文件名称不能包含在通配符的范围内(不能叫做spring-total.xml)
这里是引用
例如:总的文件(包含关系的配置文件)
分文件:
分文件:
调用总的文件:
在包含关系的配置文件中可以使用配置符(*:表示任意字符),下面这个例子,使用通配符注意不能将主文件包含在内,所以需要修改主文件的文件名称。
注意:主的配置文件不能包含在通配符的范围内(不能叫做spring-total.xml)
通过注解来完成java对象的创建,属性赋值。
1、加入maven的依赖 spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖。
使用注解必须使用spring-aop依赖
2、在类中加入spring的注解(多个不同功能的注解)
3、在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置
学习注解:@Component、@Respotory、@Service、@Controller、@Value、@Autowired、@Resource
重新创建项目:
可以设置为1.8版本
component注解的使用:
/*
* @Component:创建对象的,等同于<bean>的功能
* 属性:value就是对象的名称,也就是bean的id值,
* value的值是唯一的,创建的对象在整个spring容器中就一个
* 位置:在类的上面
* @Component(value = "mystudent")等同于
* <bean id="mystudent" class = "com.springtest.bao01.Student">
但是还需要一个功能,使用spring的配置文件声明扫描器,告诉注解的位置
* */
这里是调用的无参构造方法来创建对象
spring中和@Component功能一致,创建对象的注解还有:
1、@Repository(用在持久层的上面):放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
2、@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
3、@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的。
控制器对象,能够接受用户提交的参数,显示请求处理结果。
以上三个注解的使用语法和@Component一样的。都能够创建对象,但是这三个注解还有额外的功能。
@Repository、@Service、@Controller是用来给对象分层的用法一样角色不同
当所创建的类不是上面三种类型,使用@Component
@value:简单类型的属性赋值
/*
* @Value:简单类型的属性赋值
* 属性:value是string类型的,表示简单类型的属性
* 位置:
* 1、在属性定义的上面,无需set方法,推荐使用。
* 2、在set方法上面,用的不比较少
* */
/*
* 引用类型
* @Autowired:spring框架提供的注解,实现引用类型的赋值。
* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
* @Autowired:默认使用的是byType自动注入
* 位置:
* 1)在属性定义的上面,无需set方法,推荐使用
* 2)在set方法的上面
* */
使用byName方式:需要做的是
1、在属性上面加入@Autowired
2、在属性上面加入@Qualified(value=“bean的id”):表示使用指定名称的bean完成赋值
属性:required,是一个boolean类型的,默认true
required=true:表示如果引用类型赋值失败,程序报错,并终止执行。
required=false:表示如果引用类型赋值失败,引用类型是null,程序不报错
引用类型引用类型 AutoWired 的required属性值推荐使用 ture
Spring提供了对jdk中@Resource注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。默认是按名称注入,使用该注解,要求jdk必须是6及以上版本。
@Resource注解若不带任何参数,采用默认名称的方式注入,按名称不能注入bean,则会按照类型进行Bean的匹配注入。
下面例子首先使用byName,来赋值,但是byName不能行,左移最后使用byType方式
@Resource只使用byName方式,需要增加一个属性name
name的值是bean的id(名称)
如果不能byName赋值,那么就会报错
xml配置文件(适用于经常修改)
优点:
1、可以方便修改值,
2、对象之间的关系一目了然;
3、基于xml配置的时候,只需要修改xml即可,不需要对现有的程序进行修改。
缺点:
1、使用配置文件代码量就多,用起来费事费力。
2、解析xml的时候必然会占用资源,势必会影响到应用程序的性能;
3、xml配置文件过多,会导致维护变得困难
4、开发的时候,既要维护代码又要维护配置文件,使得开发的效率降低;
注解(适用于不经常修改)
优点:
1:注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射
2:注解和代码在一起的,之间在类上,降低了维护两个地方的成本
3:注解如果有问题,在编译期间,就可以验证正确性,如果出错更容易找
4:使用注解开发能够提高开发效率。不用多个地方维护,不用考虑是否存在“潜规则”
缺点:
1:修改的话比较麻烦。如果需要对注解进行修改的话,就需要对整个项目重新编译
2:处理业务类之间的复杂关系,不然xml那样容易修改,也不及xml那样明了
3:在程序中注解太多的话,会影响代码质量,代码简洁会有影响
4:如果后来的人对注解不了解,会给维护带来成本
5:注解功能没有xml配置齐全
可以在程序的执行过程中,创建代理对象。通过代理对象执行方法,给目标类的方法增加额外的功能(功能增强)
jdk动态代理实现步骤:
1、创建目标类,SomeServiceImpl目标类,给它的doSome,doOther增加输出时间,事务。
2、创建InvotationHandler接口的实现类,在这个类实现给目标方法增加功能。
3、使用jdk中类Proxy,创建代理对象。实现创建对象的能力。
AOP(Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程序运行过程。
AOP底层,就是采用动态代理模式实现的。采用两种代理:jdk动态代理,与CGLIB动态代理。
AOP意为面向切面编程,可通过运行期间动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
1.动态代理
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口
cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。
子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的
2.动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离。
3.Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,
让开发人员用一种统一的方式,使用动态代理。
4、AOP(Aspect Orient Programming)面向切面编程
Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
切面的特点: 一般都是非业务方法,独立使用的。
Orient:面向, 对着。
Programming:编程
OOP:即面向对象编程,本质上是一种编程思想,通过把我们编程中遇到的事物来抽象成对象来编程;
怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能
术语:
1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,
常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。
2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
5)Advice:通知,通知表示切面功能执行的时间。
说一个切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。
5.aop的实现(主要使用aspectJ)
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。
spring主要在事务处理时使用aop。
我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。
2.aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使用xml的配置文件 : 配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。
6.学习aspectj框架的使用。
1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
@Before前置通知注解-方法有JoinPoint参数()也就是切面表达式
在目标方法执行之前执行。背注解为前置通知方法,可以包含一个JoinPoint类型参数。该类型对象本身就是切入点表达式。通过该参数,可以获取切入点表达式、方法签名、目标对象。
2)表示切面执行的位置,使用的是切入点表达式。
AspectJ定义了专门的表达式用于指定切入点。表达式的原型是:
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern)方法名(参数类型和参数个数)
throws-patern抛出异常类型
?表示可选的部分
以上表达式共四个部分。
execution(访问权限 方法返回值 方发声明 (参数)异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意,表达式中黑色文字表示省略部分,各部分间用空格分开。在其中使用以下符号
举例:
execution(public * (…))
指定切入点:任意公共方法。
execution( set*(…))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service..(…))
指定切入点为:com.xyz.service包中的任意类的任意方法
execution(* com.xyz.service….(…))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“”,表示包、子包下的所有类。
execution( …service..(…))
指定所有包下所有类(接口)中所有方法为切入点
execution( .service..(…))
指定只有一级包下的service子包下的所有类(接口)中所有方法为切入点。
例如:指定以下的service包中的所有类中,所有方法为切入点。
com.service.impl
com.bjpowrnode.service.impl
cn.crm.bjpowernode.service
使用表达式为:execution( …service..*(…))
使用quickstart创建一个项目:
05Spring-aop-aspectJ:使用aspectJ框架实现aop。
使用aop:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来类的代码。
使用aspectJ实现aop的基本步骤:
1、新建maven项目
2、加入依赖
1)spring依赖
2)aspectJ依赖
3)Junit测试单元
3、创建目标类:接口和它的实现类
要做的是给类中的方法增加功能
4、创建切面类:普通类
1)在类的上面加入@Aspect
2)在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aspectj中的通知注解,例如@Before
有需要指定切入点表达式execution()
5、创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件
1)声明目标对象
2)声明切面对象
3)声明aspectJ框架中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的。
6、创建测试类,从spring容器中获取目标对象(实际上就是代理对象)。
通过代理执行方法,实现aop的功能增强。
========================
1、新建maven项目
2、加入依赖
3、创建目标类:接口和它的实现类
4、创建切片类
5、创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件
6、创建测试类,从spring容器中获取目标对象
验证proxy为代理对象,动态代理使用的是jdk动态代理方式。(目标类有接口是jdk动态代理)
自动代理生成器使用AspectJ框架内部的功能,创建目标对象的代理对象。 创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象,所以目标对象就是被修改后的代理对象,aspectj-qutoproxy:会把spring容器中的所有目标对象,一次性都生代理对象。
@Before前置通知注解-方法有JoinPoint参数()也就是切面表达式
在目标方法执行之前执行。背注解为前置通知方法,可以包含一个JoinPoint类型参数。该类型对象本身就是切入点表达式。通过该参数,可以获取切入点表达式、方法签名、目标对象。
JoinPoint(连接点):业务方法,要加入切面功能的业务方法(如果切面中需要用到方法的信息,就要加入JoinPoint)
作用是:可以在通知方法中获取方法执行时的信息,例如方法名称、方法实参。
如果你的切面中需要用到方法的信息,就加入JoinPoint。
这个JoinPoint参数的值是由框架赋予,必须是一个位置的参数
@AfterReturning:后置通知
/*后置通知定义方法,方法是实现切面功能的。
属性:
1、value切入点表达式
2、returning 自定义的变量、表示目标方法的返回值的。
自定义变量名必须和通知方法的形参名一样。
位置在方法定义的上面
特点:
1、在目标方法之后执行的。
2、能够获取目标方法的返回值,可以根据这个返回值做不同的处理功能
3、可以修改这个返回值
后置通知的定义方法,方法是实现要求:
1、公共方法public
2、方法没有返回值
3、方法名称自定义
4、方法有参数,推荐是Object,参数名自定义
@Around环绕通知(功能最强的一种通知)(掌握)
* 环绕通知方法的定义格式
@AfterThrowing异常通知-注解中有throwing属性(了解)
* 异常通知方法的定义格式
* 1、public
* 2、没有返回值
* 3、方法名称自定义
* 4、方法有一个Exception,如果还有就是JoinPoint
*@AfterThrowing:异常通知
* 属性:
* 1、value切入点表达式
* 2、throwing自定义的变量,表示目标方法抛出的异常对象。变量名必须和方法的参数名一样
* 特点:
* 1、在目标方法抛出异常时执行的
* 2、可以做异常的监控程序,监控目标方法执行时是不是有异常。如果有异常,可以发送邮件,短信进行通知
* 位置:在方法的上面定义
@After: 最终通知
* 属性:value切入点表达式
* 位置:在方法上面
* 特点:
* 1、总是会执行
* 2、在目标方法之后执行的
* 作用一般是做资源清除的
@Pointcut:定义和管理切入点
如果你的项目中有多个切入点表达式是重复的,可以复用,可以使用@Pointcut
将spring和mybatis放在一起用,主要解决的问题就是将SQLSessionFactory对象交由Spring来管理。所以,该整合,只需要将SQLSessionFactory的对象生成器SQLSessionFactoryBean注入册在Spring容器中,再将其注入给Dao的实现类即可完成整合。实现Spring与Mybatis的整合常用的方式:扫描Mapper动态代理
把myBatis框架和spring集成在一起,像一个框架一样使用。使用的技术是:ioc。
为什么IOC能够把mybatis和spring集成在一起,像一个框架一样使用?
是因为ioc能够创建对象。可以把mybatis框架中的对象交给spring统一创建,开发人员从spring中获取对象。开发人员就不用同时面对两个或者多个框架了,就面对一个spring。
mybatis使用步骤,对象
1、定义dao接口,StudentDao
2、定义mapper文件 StudentDao.xml
3、定义mybatis的主配置文件mybatis.xml
4、创建dao的代理对象,StudentDao dao = SQLSession.getMapper(StudentDao.class);
List students = dao.selecStudents();
要使用dao对象,需要使用getMapper()方法,
怎么能使用getMapper()方法,需要哪些条件
1、获取SqlSession对象,需要使用SQLSessionFactory的openSession()方法。
2、创建SqlSessionFactory对象。通过读取mybatis的主配置文件,能创建SQLSessionFactory对象。
需要SQLSessionFactory对象,使用Factory能获取SQLSession,有了SQLSession就能有dao,目的就是获取dao对象。
Factory创建需要读取主配置文件
主配置文件:
1.数据库信息:我们会使用独立的连接池类替换mybatis默认自己带的,把连接池类交给spring创建。
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123456"/>
</dataSource>
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
============================================================
通过以上的说明,我们需要让spring创建以下对象
1.独立的连接池类的对象, 使用阿里的druid连接池
2.SqlSessionFactory对象
3.创建出dao对象
需要学习就是上面三个对象的创建语法,使用xml的bean标签。
集成Mybatis的步骤:
06Spring-Mybatis:spring和mybatis的集成 步骤: 1、创建maven项目 2、加入maven依赖 1)spring 2)mybatis 3)mysql驱动 4)spring的事务的依赖 5)mybatis和spring的依赖:mybatis官方体用的,用来在spring项目中创建mybatis的SQLSessionFactory,dao对象 3、创建实体类 4、创建dao接口和mapper文件 5、创建mybatis主配置文件 6、创建Service接口和实现类,属性是dao 7、创建spring的配置文件:声明mybatis的对象交给spring创建 1)数据源 2)SqlSessionFactory 3)dao对象 8、创建测试类,获取Service对象,通过service调用dao完成数据库的访问
1、创建maven项目
2、加入maven依赖和插件
<!--单元测试--> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- spring核心IOC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- 做spring事务用到的--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <!-- mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!-- mybatis和spring集成的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <!--阿里公司的连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!--lombok快速为类对象创建set、get、构造等函数--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency> </dependencies> <build> <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中--> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <!-- 指定jdk的版本--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
3、创建实体类
@Data
public class Student {
//属性和列名一样
private Integer id;
private String name;
private String email;
private Integer age;
public Student(Integer id, String name, String email, Integer age) {//用于对对象赋值
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
}
4、创建dao接口和mapper文件
dao接口:
public interface StudentDao {
int inserStudent(Student student);
List<Student> SelectStudents();
}
mapper文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//OTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "com.Springtest.dao.StudentDao">
<insert id="insertStudent" >
insert into Student values (#{id},#{name},#{email},#{age})
</insert>
<select id="selectStudents" resultType="com.Springtest.domain.Student">
select id,name,email,age, from student order by id desc
</select>
</mapper>
例如:
<mappers>
<mapper resource="grg/auto/mapper/DepartMapper.xml"/>
</mappers>
5、创建mybatis主配置文件
<?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:控制mybatis全局行为--> <settings> <!--设置mybatis输出日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!--设置别名--> <typeAliases> <!--<typeAlias type="com.pojo.User" alias="User"></typeAlias>--> <!--name:实体类所在的包名,表示可以直接使用该包名下的实体类的大小写--> <package name="com.Springtest.domain"/> </typeAliases> <mappers> <package name="com.Springtest.dao"/> </mappers> </configuration>
6、创建Service接口和实现类,属性是dao
public class StudentServiceImpl implements StudentService { //引用类型 private StudentDao studentDao; //使用set注入,赋值 public void setStudentDao(StudentDao studentDao) { this.studentDao = studentDao; } @Override public int addStudent(Student student) { int nums = studentDao.inserStudent(student); return nums; } @Override public List<Student> queryStudents() { return null; } }
public interface StudentService {
int addStudent(Student student);
List<Student> queryStudents();
}
7、创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源
2)SqlSessionFactory
3)dao对象
<!--声明数据源DataSource,作用是连接数据库--> <bean id = "myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--set注入给DruidDataSource提供数据库信息--> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property> <property name="username" value="root"></property> <property name="password" value="admin"></property> <property name="maxActive" value="20"></property><!--连接的数量最多是20个--> </bean> <!--声明的是mybatis中提供的SQLSessionFactoryBean类,这个类内部创建SQLSessionFactory的--> <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--set注入,把数据库连接池付给dataSource属性--> <property name="dataSource" ref="myDataSource"></property> <!--mybatis主配置文件的位置 configLocation属性是Resource类型,读取配置文件 它的赋值,使用Value,指定文件的路径,使用classpath:表示文件的位置 --> <property name="configLocation" value="classpath:mybatis.xml"></property> </bean> <!--创建dao对象,使用SQLSession的getMapper(StudentMapper.class) MapperScannerConfigurer:在内部调用 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定SqlSessionFactory对象的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> <!--指定包名,包名是dao接口所在的包名。 MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法,得到每个 接口的dao对象。创建好的dao对象放入到spring的容器中的,dao对象的默认名称是接口名的首字母小写 --> <property name="basePackage" value="com.Springtest.dao"></property> </bean>
在实际开发中只需要修改dao对象bean配置文件中,指定接口所在包的位置
8、创建测试类,获取Service对象,通过service调用dao完成数据库的访问
声明service:
<!--声明service-->
<bean id="StudentService" class="com.Springtest.service.impl.StudentServiceImpl">
<!--name:属性名 ref:对象的名称 创建的对象赋值给属性,那么service就可以使用dao了-->
<property name="studentMapper" ref="studentMapper"></property>
</bean>
/*获取Service对象,通过service调用dao完成数据库的访问,执行查询操作*/
@Test
public void test4()
{
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
StudentService service = (StudentService) ctx.getBean("StudentService");
List<Student> students = service.queryStudents();
for (int i = 0; i <students.size() ; i++) {
System.out.println(students.get(i));
}
}
9、添加配置文件,对数据库进行配置,写在一个独立的文件中,编译修改数据库的配置内容。
<!--把数据库的配置,写在一个独立的文件中,编译修改数据库的配置内容
spring知道jdbc.properties文件的位置
-->
<context:property-placeholder location="jdbc.properties" />
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=admin
jdbc.maxActive=20
**问题解决:**解决通配符的匹配很全面,但是无法找到元素“context:property-placeholder”的声明,引入命名空间时报错
原因:原因是在引入命名空间时没有正确引入它的DTD解析文件。
问题:
在java代码中要写程序来控制事务,此时事务应该放在那里。
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句
通常使用JDBC访问数据库,还是mybatis访问数据库怎么处理事务
jdbc访问数据库,处理事务 Connection conn ; conn。commit();conn.rollback();mybatis访问数据库处理事务,SQLSession.commit();SqlSession.rollback();
hibernate访问数据库,处理事务,Session.commit();Session.rollback();
3问题中事务的处理方式,有什么不足
1、不同的数据库访问技术,处理事务的对象,方法不同,需要去了解不同数据库访问技术使用事务的原理,
2、掌握多重数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务
3、处理事务的多种方法
总结:就是多种数据库的访问技术,有不同的事务处理机制,对象,方法。
怎么解决不足
spring提供一种处理事务的统一模型,能使用统一步骤,方式完成多种不同的数据库访问技术的事务处理。
使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
使用spring事务处理机制,可以完成hibernate访问数据库的事务处理
处理事务,需要怎么做,做什么
spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了
1)事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
事务管理器是一个接口和他的众多实现类。
接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库—spring创建好的是DataSourceTransactionManager
hibernate访问数据库----spring创建的是HibernateTransactionManager
怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用声明就可以了
例如,你要使用mybatis访问数据库,你应该在xml配置文件中
<bean id=“xxx" class=“…DataSourceTransactionManager”>
2)你的业务方法需要什么样的事务,说明需要事务的类型。
说明方法需要的事务:
1)事务的隔离级别:有4个值。
DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。
3)事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。
*PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS*
以上三个需要掌握的
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
3)事务提交事务,回滚事务的时机
1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit
2)当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如NullPointException , NumberFormatException
3) 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException
总结spring的事务
1.管理事务的是 事务管理和他的实现类
2.spring的事务是一个统一模型
1)指定要使用的事务管理器实现类,使用
2)指定哪些类,哪些方法需要加入事务的功能
3)指定方法需要的隔离级别,传播行为,超时
你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。
spring框架中提供的事务处理方案
1.适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等
使用@Transactional的步骤:
1.需要声明事务管理器对象
2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
@Around("你要增加的事务功能的业务方法名称")
Object myAround(){
开启事务,spring给你开启
try{
buy(1001,10);
spring的事务管理器.commit();
}catch(Exception e){
spring的事务管理器.rollback();
}
}
3.在你的方法的上面加入@Trancational
2.适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中
声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。
实现步骤: 都是在xml配置文件中实现。
1)要使用的是aspectj框架,需要加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2)声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager">
3) 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
4) 配置aop:指定哪些哪类要创建代理。
举例:购买商品trans_sale项目
本例要实现购买商品,模拟用户下订单,向订单表添加销售记录,从商品表减少库存。
实现步骤:
1、创建两个数据库表sale,goods
sale销售表
goods货品表
2、添加maven依赖
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <!--单元测试--> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- spring核心IOC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- 做spring事务用到的--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <!-- mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!-- mybatis和spring集成的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <!--阿里公司的连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!--lombok快速为类对象创建set、get、构造等函数--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency> </dependencies> <build> <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中--> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <!-- —filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 --> <filtering>false</filtering> </resource> </resources> <!-- 指定jdk的版本--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
3、创建实体类
Sale,Goods
@Data
public class Goods {
private Integer id;
private String name;
private Integer amount;
private Float price;
}
@Data
public class Sale {
private Integer id;
private Integer gid;
private Integer nums;
}
4、创建dao接口和mapper文件
SaleDao接口,GoodsDao接口
响应的XML文件
Sale.xml,GoodsDao.xml
<mapper namespace="org.example.dao.GoodsDao">
<select id="selectGoods" resultType="goods">
select id,name,amount,price from goods where id = #{id}
</select>
<update id="updateGoods">
update goods set amount = amount -#{amount} where id = #{id}
</update>
</mapper>
<mapper namespace="org.example.dao.SaleDao">
<insert id="insertSale">
insert into sale(gid,nums) values(#{gid},#{nums})
</insert>
</mapper>
public interface GoodsDao {
// 更新库存
// goods表示本次用户购买的商品信息,id,购买数量
int updateGoods(Goods goods);
// 查询商品的信息
Goods selectGoods(Integer id);
}
public interface SaleDao {
// 增加销售记录(订单记录)
int insertSale(Sale sale);
}
5、创建mybatis主配置文件
<?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> <typeAliases> <!--<typeAlias type="com.pojo.User" alias="User"></typeAlias>--> <!--name:实体类所在的包名,表示可以直接使用该包名下的实体类的大小写--> <package name="org.example.domain"/> </typeAliases> <mappers> <!-- <mapper resource="com/Springtest/dao/StudentMapper.xml"/>--> <!-- 当核心配置文件mapper标签下以resource形式指向依赖配置文件时,不需要,Mapper.xml文件名称和mapper接口名称一致--> <!-- 当核心配置文件mapper标签下以class形式指向依赖配置文件时,class指向接口位置--> <!-- <mapper class="org.example.dao.SaleDao"></mapper>--> <package name="org.example.dao"/> <!-- mybatis配置文件,Mappers标签下以package包扫描形式时需要Mapper.xml文件名称和mapper接口名称一致,name是包名这个包下的所有xml文件一次性加载--> </mappers> </configuration>
6、创建异常处理方法
//自定义的运行时异常
//重写两个方法有参和无参
public class NotEnoughException extends RuntimeException{
public NotEnoughException(){
super();
}
public NotEnoughException(String message){
super(message);
}
}
7、创建Service接口和实现类
public interface BuyGoodsService {
//购买商品的方法,goodsId:购买商品的编号 ,nums:购买的数量
void buy(Integer goodsId,Integer nums);
}
public class BuyGoodsServiceImpl implements BuyGoodsService { private GoodsDao goodsDao; private SaleDao saleDao; @Override public void buy(Integer goodsId, Integer nums) {//goodsId:表示买入的商品编号,nums:表示买入的数量 System.out.println("=====buy方法的开始====="); //记录销售信息,向sale表添加记录 Sale sale = new Sale(); sale.setGid(goodsId); sale.setNums(nums); saleDao.insertSale(sale); //更新库存 Goods goods = goodsDao.selectGoods(goodsId); if (goods==null){ //商品不存在 throw new NullPointerException("编号是:"+goodsId+"的商品不存在"); }else if(goods.getAmount()<nums){ //商品库存不够 throw new NotEnoughException("编号是:"+goodsId+"的商品库存不足"); } Goods buyGoods = new Goods(); buyGoods.setId(goodsId); buyGoods.setAmount(nums); goodsDao.updateGoods(buyGoods); System.out.println("=====buy方法的完成====="); } //set方法完成属性的赋值 public void setGoodsDao(GoodsDao goodsDao) { this.goodsDao = goodsDao; } public void setSaleDao(SaleDao saleDao) { this.saleDao = saleDao; } }
8、创建spring的配置文件:声明mybatis的对象交给spring创建
<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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"> <!--把数据库的配置,写在一个独立的文件中,编译修改数据库的配置内容 spring知道jdbc.properties文件的位置 --> <context:property-placeholder location="jdbc.properties" /> <!--声明数据源DataSource,作用是连接数据库--> <bean id = "myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--set注入给DruidDataSource提供数据库信息--> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="maxActive" value="${jdbc.maxActive}"></property><!--连接的数量最多是20个--> </bean> <!--声明的是mybatis中提供的SQLSessionFactoryBean类,这个类内部创建SQLSessionFactory的--> <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--set注入,把数据库连接池付给dataSource属性--> <property name="dataSource" ref="myDataSource"></property> <!--mybatis主配置文件的位置 configLocation属性是Resource类型,读取配置文件 它的赋值,使用Value,指定文件的路径,使用classpath:表示文件的位置 --> <property name="configLocation" value="classpath:mybatis.xml"></property> </bean> <!--创建dao对象,使用SQLSession的getMapper(StudentMapper.class) MapperScannerConfigurer:在内部调用 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定SqlSessionFactory对象的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> <!--指定包名,包名是dao接口所在的包名。 MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法,得到每个 接口的dao对象。创建好的dao对象放入到spring的容器中的,dao对象的默认名称是接口名的首字母小写 --> <property name="basePackage" value="org.example.dao"></property> </bean> <!--声明service--> <bean id="BuyGoodsService" class="org.example.service.impl.BuyGoodsServiceImpl"> <!--name:属性名 ref:对象的名称 创建的对象赋值给属性,那么service就可以使用dao了--> <property name="goodsDao" ref="goodsDao"></property> <property name="saleDao" ref="saleDao"></property> </bean> </beans>
9、创建测试类,获取Service对象
通过增加事务:使数据库的操作处于一种一致的状态之下,添加成功了那么库存就应该更新,如果有一个失败了,那么整个操作需要撤销需要通过事务来进行操作。给buy方法添加事务,它在执行过程中会涉及到多个数据库的操作,buy方法需要添加事务。
如果不添加事务:就会导致sql语句执行不一致,导致最终的结果不正确。,以下实例如果没有添加事务,购买不存在的商品会添加记录到销售表中,而后报错,不会执行,更改库存的sql操作,那么就会导致,两张表的执行不一致。
@Override public void buy(Integer goodsId, Integer nums) {//goodsId:表示买入的商品编号,nums:表示买入的数量 System.out.println("=====buy方法的开始====="); //记录销售信息,向sale表添加记录 Sale sale = new Sale(); sale.setGid(goodsId); sale.setNums(nums); saleDao.insertSale(sale); //更新库存 Goods goods = goodsDao.selectGoods(goodsId); if (goods==null){ //商品不存在 throw new NullPointerException("编号是:"+goodsId+"的商品不存在"); }else if(goods.getAmount()<nums){ //商品库存不够 throw new NotEnoughException("编号是:"+goodsId+"的商品库存不足"); } Goods buyGoods = new Goods(); buyGoods.setId(goodsId); buyGoods.setAmount(nums); goodsDao.updateGoods(buyGoods); System.out.println("=====buy方法的完成====="); }
测试代码:
@Test
public void test01()
{
String config = "applicationContext.xml";
ApplicationContext cxt = new ClassPathXmlApplicationContext(config);
// 从容器中获取service
BuyGoodsService buyGoodsService = (BuyGoodsService) cxt.getBean("BuyGoodsService");
// 调用方法
// buyGoodsService.buy(1001,10);
buyGoodsService.buy(1001,200);
}
测试结果:
通过aop的机制给buy方法增加事务
spring框架中提供的事务处理方案
1、适合中小项目使用的,注解方案。
spring框架自己用aop实现给业务方法增加事务的功能,使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
所有属性如下:
propagation:用于设置事务传播属性。该属性类型为Propagation枚举,默认值为Propagation.REQUIRED。
isolation:用于设置事务的隔离级别。该属性类型为Isolation枚举,默认值为Isolation.DEFAULT。
readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为boolean,默认值为false。
timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为int,默认值为-1,即没有时限。
rollbackFor:指定需要回滚的异常类。类型为Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
通过@Transactional注解方式,可将事务织入到相应的public方法中,实现事务管理。
使用@Transactional注解的步骤:
1、声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager">
2、开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知别人已经在里面写过了,不用自己写
@Around(“你要增加的那个事务功能的业务方法名称”)
object myAround(){
开启事务,spring给你开启
try{
buy(1001,10);
spring的事务管理.commit();
}catch(Exception){
spring的事物管理.rollback();
}
}
3、在你的方法上面加入@Transactional注解
步骤:
1、声明事务管理器对象
<!--使用spring的事务处理-->
<!--1、声明spring的事务管理器,完成事务提交和事务回滚的-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接数据库,指定数据源-->
<property name="dataSource" ref="myDataSource"/>
</bean>
2、开启事务注解驱动
<!--2、开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象transaction-manager:事务管理器对象的id-->
<tx:annotation-driven transaction-manager="transactionManager"/>
3、在方法上面加入以下@Transactional注解,其中的设置都是默认值,默认的传播行为、默认的隔离级别、默认抛出运行时异常回滚事务,或者直接加入@Transactional。
rollbackFor:表示发生指定的异常一定回滚。
处理逻辑是:
1、spring框架会首先检查出方法抛出异常是不是在rollbackFor的属性值中,如果异常在rollbackFor列表中,不管是什么类型的异常,一定回滚。
2、如果你的抛出的异常不在rollbackFor列表中,spring会判断异常是不是RuntimeException,如果是一定回滚。
@Transactional(//rollbackFor,当发生指定异常时,会回滚
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
rollbackFor = {
NullPointerException.class,NotEnoughException.class
}
)
有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。
实现步骤:
都是在xml配置文件中实现的。
1、要使用aspectj这个框架,加入依赖
<!--aspectj依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、声明事务管理器对象
<!--声明式事务处理:和源代码完全分离的-->
<!--1、声明事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource"></property>
</bean>
3、声明方法需要配置事务类型(配置方法的事务属性(1、隔离级别 2、传播行为 3、超时 ))
<tx:advice id = "myAdvice" transaction-manager="transactionManager">
<!--tx:attributes:配置事务属性-->
<tx:attributes>
<!--tx:method :给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
name: 方法名称 1、完整的方法名称,不带有包和类
2、方法可以使用通配符,*表示任意字符(适用于多个方法来指定很多的方法)
propergation:传播行为,枚举值
isolation: 隔离级别
rollback-For:你指定的异常类名,全限定类名。发生异常一定回滚
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.NullPointerException,org.example.excep.NotEnoughException"/>
</tx:attributes>
</tx:advice>
4、配置aop:声明那些类需要创建代理。
<aop:config>
<!--配置切入点表达式:指定那些包中类,要用事务
id:切入点表达式的名称,唯一值
expression:切入点表达式,指定那些类要使用事务,aspectj会创建代理对象
com.example.service
com.service
com.crm.service
-->
<aop:pointcut id="servicePT" expression="execution(* org.example.service.impl.BuyGoodsServiceImpl*.*(..))"/>
<!--配置增强器:关联advice和pointcut-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePT"></aop:advisor>
</aop:config>
5、测试代码:
@Test
public void test01()
{
String config = "applicationContext.xml";
ApplicationContext cxt = new ClassPathXmlApplicationContext(config);
// 从容器中获取service
BuyGoodsService buyGoodsService = (BuyGoodsService) cxt.getBean("BuyGoodsService");
System.out.println("service是代理:"+buyGoodsService.getClass().getName());
// 调用方法
// buyGoodsService.buy(1001,10);
buyGoodsService.buy(1001,10);
}
service是代理,说明完成了事务管理。
在web项目中怎么使用容器对象。
实例:在web项目中使用spring,完成学生注册功能
实现步骤:
1、创建一个maven,web项目
2、添加依赖(拷贝依赖,添加jsp、servlet依赖)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <!--单元测试--> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- spring核心IOC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- 做spring事务用到的--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <!-- mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!-- mybatis和spring集成的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <!--阿里公司的连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!--lombok快速为类对象创建set、get、构造等函数--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency> <!--servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <!--jsp依赖--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> </dependency> </dependencies> <build> <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中--> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <!-- —filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 --> <filtering>false</filtering> </resource> </resources> <!-- 指定jdk的版本--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
3、拷贝06Spring-mybatis的代码和配置文件
4、创建index.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>注册学生</p> <form action="" method="post"> <table> <tr> <td>id:</td> <td><input type="text" name="id"></td> </tr> <tr> <td>姓名:</td> <td><input type="text" name="name"></td> </tr> <tr> <td>email:</td> <td><input type="text" name="email"></td> </tr> <tr> <td>年龄:</td> <td><input type="text" name="age"></td> </tr> <tr> <td></td> <td><input type="submit" value="注册学生"></td> </tr> </table> </form> </body> </html>
查看web.xml
再将名称修改为web.xml
4、创建一个jsp发起请求,有参数id、name、email、age
5、创建Servlet,接收请求参数,调用Service,调用dao完成注册
6、创建一个jsp作为显示结果页面
结果演示:
首先注册一个学生
创建了一次容器对象
然后再次注册一个学生
再次创建了一个容器对象(不同的对象)。
如果文件中有很多对象,那么创建效率就很慢,占用多余的内存。
容器对象包含所有对象,只需要创建一次就可以了。如何操作?
需求在web项目中,容器对象只需要创建一次,把容器对象放入到全局作用域ServletContext中。
监听器作用:
1、创建容器对象,执行ApplicationContext ctx = new ClassPathXMLApplicationContext(“applicationContext.xml”);
2、把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)
监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener
private WebApplicationContext context;
public interface WebApplicationContext extends ApplicationContext
ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象
把创建的容器对象,放入到全局作用域
key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
value:this.context
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
为了使用监听器对象:
1、要加入依赖
<!--为了使用监听器对象,加入依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、注册监听器ContextLoaderListener(web.xml文件)
<!--注册监听器ContextLoaderListener
监听器被创建爱你对象后,会读取/WEB-INF/applicationContext.xml
为什么要读取文件:因为在监听器中要创建ApplicationContext对象,需要加载配置文件。
/WEB-INF/applicationContext.xml就是监听器默认读取的spring配置文件的路径
可以修改默认的文件位置,使用配置项context-param重新指定文件的位置
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--自定义配置文件的路径-->
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3、使用监听器(在Servlet代码中使用)
WebApplicationContext ctx = null;
//获取ServletContext中的容器对象,创建好的容器对象,拿来就用
String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
Object attr = getServletContext().getAttribute(key);
if (attr!= null){
ctx = (WebApplicationContext) attr;
}
System.out.println("容器对象的信息======="+ctx);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。