为了解耦合:让类与类、模块与模块之间关系更松散
spring适合管理哪些对象:service对象、dao对象、工具类对象
spring不适合管理哪些对象:实体类、(servlet、listener、filter等web对象也不适合,因为这些对象是给tomcat创建和管理的)
spring又叫容器,是装Java对象。可以控制spring创建Java对象、给属性赋值
可以当作容器的对象---tomcat服务器----管理servlet、listener、filter对象
手动下载对应的spring版本:https://repo.spring.io/ //实际项目使用Maven自己会处理的
docs:文档
libs:源代码(spring是开源的) //spring比较大,分成20多个独立的模块,为了方便使用每模块做成单独的jar包
.jar 字节码打包
javadoc.jar 文档打包
sources.jar Java源代码打包
schena: spring框架使用的约束文件
Core Container:核心容器,包含4个模块
IOC:控制反转
是一个理论思想:把对象的创建、属性赋值、对象的生命周期都交给代码以外的容器管理
控制:对象创建、属性赋值、对象的生命周期
反转:开发人员管理对象的权限转移给代码之外的容器实现。由容器完成对象的管理
正转:开发人员 new 构造方法创建对象。由开发人掌握对象的创建、属性赋值、对象的生命周期。
开发人员通过容器可以使用容器中的对象
技术实现:DI (依赖注入)-----程序只需要提供使用对象的名字,对象如何创建、如何从容器中查找、获取都由容器内部自己实现
依赖:A类用了B类的内容 (执行A类的功能,需要先创建B类的对象)
注入:赋值 (B类对象作为A类的属性)
Spring框架使用DI来实现IoC思想,通过名字获取容器中对应的对象(spring底层使用反射机制创建对象、给属性赋值)
IoC通过管理对象解耦合。解决处理业务逻辑对象之间的耦合关系,也就是service对象和dao对象
使用: 1.使用maven创建普通的Java项目后,修改pom.xml文件加入spring依赖Spring-context //依赖代码去Maven官网找
2.开发人员写自己的业务代码(类)
3.创建spring配置文件xml(声明对象:一个<bean>表示一个Java对象)把对象交给spring创建和管理
4.创建spring容器对象ApplicationContext接口//代表配置文件,从容器对象中根据名称获取对象getBean("id值")
spring配置文件一般会起名beans.xml 或applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--beans根标签
跟标签后面的属性是约束文件的说明
xmls 声明命名空间
xmlns:xsi 命名xsi空间
xsi:schemaLocation xsi空间里有个标签schemaLocation
http://www.springframework.org/schema/beans 约束文件的具体路径
http://www.springframework.org/schema/beans/spring-beans.xsd 互联网上的约束文件的地址
-->
<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">
<!--声明对象
bean标签:spring管理的java对象
id:自定义的对象名
class:全类名,通过反射创建对象用的
spring根据id、class创建对象,把对象放到spring的map对象中 //map.put(id,对象)
-->
<bean id="对象名" class="全类名">
</beans>
/*1.指定spring的配置文件路径,从类路径classes下,因为代码编译后放在target/classes之下,而resources的文件也是放在这*/
String config = "beans.xml";
/*2.创建容器对象: ApplicationContext接口。 ClassPathXmlApplicationContext实现类,从类路径中读取配置文件*/
//在这步时调用无参构造创建对象。即创建容器对象时读取配置文件,创建文件中的所有的声明对象<bean>,然后放到容器的map中
//好处是以后用的时候因为容器中已经有对象了,所以获取速度快。缺点是可能浪费性能
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
/*3.从容器中获取指定名称的对象(bead中的id值),类型为Object,需要转回自己的类型*/
SomeService service = (SomeService) ctx.getBean("id值");
/*4.调用接口类型对象的方法*/
service.doSome();
int count = ctx.getBeanDefinitionCount(); //获取对象的数量
String[] names = ctx.getBeanDefinitionNames(); //获取对象的名字字符串数组
DI:给属性赋值
方式
- 基于配置文件
- 基于注解
DI分类:
- set注入 //设值注入 spring调用无参构造方法创建对象。调用类的set方法,在set方法中完成属性赋值 //必须有set方法,本质来讲执行的是set属性名(),与属性名无关
- 构造注入 spring调用构造方法时完成属性赋值
基于配置文件的ID:
1.配置文件、set注入
<bean id="" class="">
<!--简单类型set注入 (简单类型:基本类型、String类型)-->
<property name="属性名" value="属性值"/> //name值与set+属性名()方法相关,与属性无关
<!--引用类型set注入-->
<property name="属性名" ref="对象名,即对象的id值"/>
</bean>
2.配置文件、构造注入
<bean标>的<constructor-arg>:表示构造方法的1个参数
name:形参名
index:构造方法参数位置 0开始
value:简单类型实参
ref:引用类型实参
<bean id="" class="">
<constructor-arg name="形参名" value="简单类实参"/> 将value值赋给形参
<constructor-arg name="形参名" ref="引用类型实参"/>
<constructor-arg index="下标位置" value="简单类实参"/>
<constructor-arg index="下标位置" ref="引用类型实参"/>
</bean>
3.引用类型自动赋值:
autowire属性:该对象的引用类型采取自动赋值
值:byName、byType
<bean id="" class="" autowire=""></bean>
引用类型的自动注入:<bean>带有属性autowire="byName或byType"
- byName:Java类中引用类型属性名和spring容器的<bean>的id值相同、类型也相同。这样<bean>能赋值给属性
- byType:Java类中引用类型的数据类型和spring容器的<bean>是同源关系。这样<bean>能赋值给属性 //前提是<bean>对象只在该类型中有一个,不然类的属性就不知道赋值哪个了
- 同源关系: 属性的类型和<bean>的类型:相同、继承关系、接口实现
多个Spring配置文件:按功能模块分、按类的功能分
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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">
<!--其他配置文件-->
<import resource="classpath:其他文件的类路径"/>
<import resource="classpath:可以同通配符*表示一段文字"/>
</beans>
基于注解的ID
创建对象的注解 (234注解都是扩展自Component注解) @Component 位置:类上 创建Java对象,相当于<bean> @Repository 位置:dao接口的类上 创建dao接口的类的对象--dao对象(持久层对象),能访问数据库 @Service 位置:放在业务层接口的实现类上 创建业务层对象,业务层对象有事务的功能 @Controller 位置:放在控制器接口的实现类上 创建控制器对象(表示层对象),控制器对象能接受请求、把请求的处理结果显示给用户 属性:value 表示对象的名称,即id值 //可省略value属性名、可不提供该属性,默认对象名为 类名的小驼峰形式 @Component(value = "对象名") @Component("对象名") @Component
属性赋值注解 @Value 简单类型属性值 位置:1)属性定义上面,无需set方法 2)set方法上面,需要set方法 属性:value 表示简单类型属性值(可以使用属性配置文件的key-value) @Value(value = "属性值") @Value("属性值") @Value(value = "${key值}") @Autowired 引用类型属性赋值,使用自动注入原理(byName、默认byType) 位置:同上 //使用byName:再加上一个注解@Qualifier(value = "bean的id值")或@Qualifier("bean的id值")表示把该名的对象赋值给该属性 属性:required 值为:false、true默认 (spring启动时创建容器对象会检查引用类型属性是否赋值成功,如果true会报错停止,false会是默认null不报错正常执行)@Resource 该注解不是Spring的,是JDK的,spring支持该注解使用。引用类型属性赋值,使用自动注入原理(默认byName、byType) 位置:同上 //先使用byName,如果失败再使用byType //高于JDK1.8,JDK不带该注解,需要加入依赖:Maven中央仓库中的Javax Annotation APIJava通用注解 属性:name 只使用byName的方式,指定对象名 @Resource(name = "bean的id值")
使用注解要在配置文件中声明组件扫描器: 框架会扫描这个包和其子包内的所有类,找到类的注解,按照注解的功能创建对象、属性赋值
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--组件扫描器:扫描一个包-->
<context:component-scan base-package="注解所在的包名"/>
<!--组件扫描器:扫描多个包,所有分号、逗号、空格来分隔包-->
<context:component-scan base-package="包名1;包名2,包名3 包名4"/>
<!--组件扫描器:扫描多个包,使用父包-->
<context:component-scan base-package="包名1;包名2,包名3 包名4"/>
<!--在注解中读取属性配置文件:即.properties文件,这样就能在注解中使用key-value数据了-->
<context:property-placeholder location="classpath:类路径"/>
</beans>
XML好处是代码与数据分离,方便使用
缺点是配置文件过于繁琐,不利于开发维护
注解好处是方便开发省事可读性好
缺点是代码与数据不分离,每次改完需要重新编译
AOP
AOP:面向切面编程:
1)设计项目时,找出切面的功能
2)安排切面的执行时间(目标方法执行前后)
3)执行位置(哪个类、哪个方法增加切面)
AOP思想技术实现:1)spring框架实现类AOP思想的部分功能,但是很繁琐,一般都是框架自己用不是开发人员用
2)Aspectj:独立框架(spring框架了集成该框架,通过spring可以间接用),专门做AOP
AOP是一种动态的技术思想,实现业务功能与非业务功能的解耦合,让业务功能成为独立模块,其他功能成为独立模块,达到可以复用的目的。
当目标方法不能修改时,在执行期间通过AOP技术生成代理对象,代理业务功能的同时增加功能
JoinPoint连接点:连接切面的业务方法(目标类的方法),在业务方法执行时会执行切面的功能
Pointcut切入点:一个或多个连接点的集合, //表示位置
Advice通知/增强:在目标方法执行之前还是之后执行 // 表示时间
Aspect切面:给业务方法(目标类方法)增加的功能,一般都是非业务功能、可以复用的 // 表增加的功能
target目标对象:给哪个对象增加切面功能
动态的思想:在程序运行时,创建代理,使用代理方法增加切面功能。
Aspectj框架使用方式:1)注解 2)XML配置文件 //Maven项目中,spring继承Aspectj,只需在pom.xml中加入其依赖就可以:spring-aspectj
通知Advice:即时间方面的注解
@Before:前置通知 位置:切面方法上 //目标方法执行之前执行,不会影响目标方法的执行,不会修改目标方法的结果
(方法:public、void、可选型参1:JoinPoint类型,表示正在作用的目标方法(连接点)。相当于反射的Method。可以查看目标方法的信息)
属性:value 表示切入点表达式,来确定切面执行的位置@Before(Value = "切入点表达式")@AfterReturning:后置通知 位置:切面方法上 //目标方法执行之后执行,不会影响目标方法的执行,可以获取目标方法的返回结果
(方法:public、void、可选型参1:JoinPoint类型、自定义形参:推荐Object类型,表示目标方法的返回值)
属性: value 表示切入点表达式,来确定切面执行的位置
returning 自定义变量,表示目标方法的返回值。必须和通知方法的形参名一致@AfterReturning(Value = "切入点表达式",returning = "自定义变量名")@Around:环绕通知 位置:切面方法上 //执行代理目标方法:执行切面方法,返回切面方法的返回值
//切面方法里可以控制目标方法的执行:ProceedingJoinPoint对象.proceed()
//切面方法里可以对目标方法的执行结果进行操作,任何返回想要的数据
//切面方法里可以在目标方法执行的上下添加功能
(方法:public、返回值:推荐Object,表示调用目标方法希望得到的结、
形参:ProceedingJoinPoint接口类型,该接口继承JoinPoint接口,相当于反射中的Method,用来执行目标方法的,ProceedingJoinPoint对象.proceed()相当于method.invoke() )
属性:value 表示切入点表达式,来确定切面执行的位置@Around(value = "切入点表达式")
@AfterThrowing:异常通知 //了解即可//目标方法抛出异常后执行。能获取目标方法的异常现象。不是异常处理程序,可以得到发生异常的通知,可以看作目标方法的监控程序
(方法:public、void、形参:Exception类型、可选型参1:JoinPoint类型)
属性:value 表示切入点表达式,来确定切面执行的位置
throwing 自定义变量,表示目标方法抛出的异常,变量名必须和切面方法的形参Exception的名相同
@After:最终通知 //了解即可 目标方法执行之前执行。无论目标方法是否抛出异常,该增强均会被执行。
(方法:public、void、可选型参1:JoinPoint类型)
属性:value 表示切入点表达式,来确定切面执行的位置
Pointcut位置:使用Aspectj切入点表达式 execution(访问修饰符 返回值类型 包名类名方法名(参数类型)) 异常类型) //红色表示该区域可以省略
*:0或多个任意字符
..:1)参数中表任意个数、类型 2)包名后表当前包及子包路径
+:1)类名后表当前类及子类 2)接口后表当前接口及实现类
//切入点表达式可以表示方法定义说明
使用:
- 创建业务接口,实现目标类
- 创建切面类(普通的类),创建切面(方法)
- 在切面类上加注解@Aspectj //切面类注解:表示切面功能的类
- 在切面类的方法上加入Aspectj框架的通知注解 // 所有的切面方法都一个可选的型参1:JoinPoint类型
//该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。
//如: 对象.getArgs()返回通知方法参数列表 对象.getSignature()返回连接点签名- 在spring配置文件中:
- 声明目标类对象 <bean>
- 声明切面类对象 <bean>
- 声明自动代理生成器 <aop:aspectj-autoproxy /> //调用Aspectj框架的功能寻找容器中的所有对象,把每个目标对象加入切面类中的功能,生成代理
//每个代理对象是---修改了 的内存中的目标对象,这个目标对象就是代理对象- 创建测试类,测试目标方法执行时参加的切面功能
@Pointcut 辅助的注解,用来定义和管理切入点(多个切入点表达式重复,可以复用)
位置:自定义方法上面,这个方法可以看作是切入点表达式的别名,在其他的通知注解中可以使用该方法名---就表示这个切入点表达式
(一般在切面类自定义一个私有方法方法)
属性:value 表示切入点表达式,来确定切面执行的位置,此时该注解的方法的方法名就是该value值---切入点表达式@Pointcut(value = "切入点表达式") 在通知注解中使用:@Before(Value = "方法名()")
Spring集成MyBatis
spring能集成很多框架,能让开发人员使用其他框架更方便
集成使用的是:spring IoC技术
使用mybatis需要创建mybatis中的对象-----Dao接口的代理对象
1)需要用到:SqlSession对象.getMapper(dao接口.class)得到dao对象
需要SqlSessionFactory,创建SqlSessionFactory对象,才能openSession()得到SqlSession对象
2)需要DataSource对象,功能更强大的的连接池对象代替mybatis自己的PooledDataSource
集成的步骤:
1)创建maven项目,加入依赖:spring依赖、mybatis依赖、MySQL驱动、junit单元测试、阿里的druid连接池
mybatis-spring依赖:mybatis官网提供,用来在spring项目中,创建mybatis对象
spring有关事务的依赖
mybatis与spring整合时,事务是自动提交的
mybatis:
2)创建实体类 //与表的列名对应
3)创建Dao接口和mapper文件写sql语句
4)写mybatis主配置文件
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>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--声明别名-->
<typeAliases>
<package name="包名" >
</typeAliases>
<!--指定其他mapper文件的位置:为了找到其他文件中的sql语句-->
<mappers>
<package name="mapper文件所在的包名" />
</mappers>
</configuration>
5)创建service接口和他的实现类,类方法就是操作dao //mvc 别忘了实现类的私有属性是dao接口哦
6)创建spring配置文件
1.声明数据源DataSource,使用阿里的Druid连接池 // DruidDataSource配置 · alibaba/druid Wiki · GitHub 参考配置
配置url、username、password这三项 //Druid会自动跟url识别驱动类名,所以不需要配置属性driverClassName
2.声明SqlSessionFactoryBean类(mybatis提供的),在类内部创建SqlSessionFactory对象 //mybatis-spring依赖提供了SqlSessionFactoryBean类
3.声明MapperScannerConfiguration类,在类内部创建dao代理对象 //创建好的对象都放到spring容器中
4.声明Service对象,把 3.的dao赋值给service对象的属性 //mvc
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--声明数据源DataSource -->
<!--init是初始方法,会在构造方法执行完毕后自动调用,在DruidDataSource类中存在 close是销毁方法,在容器销毁时会调用该方法,用来把内存中的连接对象删除掉
这俩方法都是在DruidDataSource类中定义好的方法名-->
<bean id=" " class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/数据库" />
<property name="username" value="用户" />
<property name="password" value="密码" />
</bean>
<!--声明数据源方式二:灵活方式、加载外部属性配置文件--使用变量-->
<context:property-placeholder location="classpath:xxx.properties">
<bean id=" " class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc的key值}"/>
<property name="username" value="${用户名的key值}" />
<property name="password" value="${密码的key值}" />
</bean>
<!--声明SqlSessionFactoryBean,在这个类内部创建SqlSessionFactory-->
<bean id=" " class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定数据源头数据源 -->
<property name="dataSource" ref="数据源对象id" />
<!--指定mybatis主配置文件//因为用来mybatis数据源是是主配置里写的,集成框架改在spring配置文件了,要关联一下
Resource可以直接使用value属性赋值-->
<!--主配置文件路径 classpath:xxx.xml 类路径下的.xml-->
<property name="configLocation" value="主配置文路径" />
</bean>
<!--声明MapperScannerConfiguration-->
<!--MapperScannerConfiguration作用是循环basePackage所表示的包名,把包中的每个接口都找到,
调用SqlSession对象.getMapper(dao接口.class)创建出代理对象,把代理对象放到容器里(代理dao对象在容器的名是接口名的小驼峰)-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfiguration">
<!--指定SqlSessionFactory对象的名称 -->
<property name="SqlSessionFactoryBeanName" value="上面SqlSessionFactoryBean的id值" />
<!--创建dao代理对象 要参加对象就得有SqlSession对象.getMapper(dao接口.class)中的dao接口.class,所以要指定dao接口所在的包名-->
<property name="basePackage" value="dao接口的包名" />
</bean>
<!--声明service-->
<bean id=" " class="service实现类全名">
<property name="类的属性名(dao接口作为的service对象属性)" ref="创建dao代理对象(即接口的小驼峰)" />
</bean>
</beans>
7)测试dao访问数据库
spring事务的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
mybatis-spring集成依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
德鲁伊连接池
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
插件:
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
事务
事务放在service类的业务方法(public)之上
因为不同技术做事务是不同的:jdbc、mybatis -------语句都不一样,所需需要有一个统一的方法:spring统一管理事务,把不同的数据库访问技术统一起来
spring事务管理器:是一个接口 PlatformTransactionManager
方法:
commit() 提交事务
rollback() 归滚事务
getTransaction() 获取事务状态
实现类:该接口有很多实现类,一个实现类代表一种数据库访问技术,有实现类完成事务的提交、回滚
实现类创建出的事务管理器器对象:管理不同的数据库访问技术的事务处理 //由spring做提交、回滚
实现类:
DataSourceTransactionManager //使用 JDBC 或 My Batis 进行 数据库操作 时使用。
HibernateTransactionManager //使用 Hibernate 进行持久化数据时使用。
事务的提交、回滚的时机:业务方法抛出运行时异常,事务回滚。其他清空事务提交
事务使用的AOP的环绕通知:spring在目标方法前和后都增强功能,不需要修改代码 //在业务方法上增加切面功能
@Around(所有的业务方法)
public xxx 切面方法(传入业务方法){
try{
使用spring业务管理器开启事务 // PlatformTransactionManager对象.beginTransaction()
执行目标方法 //业务方法
业务正常执行,提交事务 //PlatformTransactionManager对象.commit()
}catch(Exception){
若出异常,回滚事务 //PlatformTransactionManager对象.rollback()
}
}怎样让spring知道哪些业务方法有事务?
TransactionDefinition接口:定义了事务描述相关的三类常量:
事务隔离级别:定义了五个事务隔离级别常量
ISOLATION_DEFAULT:采用 DB 默认的事务隔离级别。 MySql 的默认为 RE PEAT ABLE_READ、 Oracle默认为 READ_COMMITTED 。
ISOLATION_READ_UNCOMMITTED:读未提交。未解决任何并发问题。
ISOLATION_READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
ISOLATION_REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
ISOLATION_SERIALIZABLE:串行化。不存在并发问题。
事务传播行为: 业务方法在调用时,事务在方法之间的传递和使用 //可以标识方法有没有事务
PROPAGATION_REQUIRED:默认的播行为。必须在事务内执行。若当前环境存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务,在新事务中执行
PROPAGATION_REQUIRES_NEW:方法需要一个新事务。调用方法,方法当前环境存在一个新事务,则当前环境的事务暂停,知道新事物执行完毕。
方法当前环境若不存在事务,则新建一个事务,在新事物中执行
PROPAGATION_SUPPORTS:当前环境有事务就支持事务,当前环境没事务也可以正常执行
不用掌握:
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
事务默认超时时限: 一个业务方法最长的执行时间,到达时间没有执行完毕,spring会回滚事务 //以秒为单位。默认-1,没有超时时间
TIMEOUT_DEFAULT
方式一:使用 Spring 的事务注解管理事务------通过spring自己的注解@Transactional 注解方式, 可将事务注入到相应 public 方法中,实现事务管理。
特点:适合中小型项目:因为注解在要在源代码写,但使用方便
spring自己提供的事务控制
@Transactional 位置:1)放在业务方法(publice)之上 2)类上 (相当于所有public方法都加) //控制(隔离级别、传播行为、超时)
@Transactional(属性=属性值,属性=属性值,属性=属性值,……) //使用设置的值
@Transactional //使用的时默认值
属性:propagation 事务传播属性。该属性值为:Propagation 类的枚举值 //默认值为Propagation.REQUIRED
isolation 事务的隔离级别。该属性为 Isolation 类的枚举值 //默认值为Isolation.DEFAULT
readOnly 该属性为 布尔值。用于设置该方法对数据库的操作是否是只读的。 //默认值为 false 不是只读 //只读:只查不改
timeout 超时时限。单位为秒,类型为 int //默认值为-1 ,即没有时限。
回滚:先查看是异常是否在列表中,如果在一定回滚。如果抛出的异常不再列表,会检查异常是否为运行时异常,若是则回滚
rollbackFor 回滚的异常类列表--->类型为 Class[] //类类型 //默认值为空数组 //只有一个异常类时,可以不使用数组
表示当方法抛出设置在列表里的异常类时,要进行回滚
rollbackForClassName 回滚的异常类列表---->String[] //字符串类型,指定需要回滚的异常类类名 //默认值为空数组 //只有一个异常类时,可以不使用数组
不回滚:
noRollbackFor 指定不需要回滚的异常类列表 --->类型为 Class[] //默认值为空数组 //只有一个异常类时,可以不使用数组
noRollbackForClassName 指定不需要回滚的异常类类名--->类型为 String[] //默认值为空数组 //只有一个异常类时,可以不使用数组
使用步骤:1)在spring的配置文件,声明事务的内容:声明事务管理器--->说明使用哪个事务管理器对象
声明使用注解管理事务:开启注解驱动
<?xml version="1.0" encoding="UTF-8"?> <beans> <!--声明数据源--> <bean id=" " class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="jdbc:mysql://localhost:3306/数据库" /> <property name="username" value="用户" /> <property name="password" value="密码" /> </bean> <!--声明SqlSessionFactoryBean,在这个类内部创建SqlSessionFactory--> <bean id=" " class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="数据源对象id" /> <property name="configLocation" value="主配置文路径" /> </bean> <!--声明MapperScannerConfiguration--> <bean class="org.mybatis.spring.mapper.MapperScannerConfiguration"> <property name="SqlSessionFactoryBeanName" value="上面SqlSessionFactoryBean的id值" /> <property name="basePackage" value="dao接口的包名" /> </bean> <!--声明service--> <bean id=" " class="service实现类全名"> <property name="类的属性名(dao接口作为的service对象属性)" ref="创建dao代理对象(即接口的小驼峰)" /> </bean> <!--声明事务的控制:--> <!--1.声明事务管理器 起一个语义化id名,一般为transactionManager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--指定数据源DataSource--> <property name="dataSource" ref="数据源对象id" /> </bean> <!--可以有多个事务管理器,因为可以有多个数据源--> <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="数据源对象id" /> </bean> <!--2.开启事务注解驱动:告诉框架使用注解管理事务 会加入spring-tx.xsd文件--> <!--事务管理驱动也可以指定不同的事务管理器--> <tx:annotation-driven transaction-manager="事务管理器id"/> </beans>
2)正在类的源代码中加入 @Transactional
方式二:使用 AspectJ 的 AOP 配置文件中来声明事务控制---声明式事务
特点:不用该源代码,代码和事务是分开的,适合大项目
不容易理,解配置复杂
使用步骤:1)在pom.xml加入AspectJ 依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2)在spring配置文件声明事物的内容
1.声明业务管理器
2.声明业务方法需要的事务属性
3.声明切入点表达式
<?xml version="1.0" encoding="UTF-8"?> <beans> <!--声明数据源--> <bean id=" " class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="jdbc:mysql://localhost:3306/数据库" /> <property name="username" value="用户" /> <property name="password" value="密码" /> </bean> <!--声明SqlSessionFactoryBean,在这个类内部创建SqlSessionFactory--> <bean id=" " class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="数据源对象id" /> <property name="configLocation" value="主配置文路径" /> </bean> <!--声明MapperScannerConfiguration--> <bean class="org.mybatis.spring.mapper.MapperScannerConfiguration"> <property name="SqlSessionFactoryBeanName" value="上面SqlSessionFactoryBean的id值" /> <property name="basePackage" value="dao接口的包名" /> </bean> <!--声明service--> <bean id=" " class="service实现类全名"> <property name="类的属性名(dao接口作为的service对象属性)" ref="创建dao代理对象(即接口的小驼峰)" /> </bean> <!--声明式事务:--> <!--1.声明事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--指定数据源DataSource--> <property name="dataSource" ref="数据源对象id" /> </bean> <!--2.:配置事务通知:声明业务方法的事务属性(隔离级别、传播行为、超时)--> <!--id:给业务方法配置事务段代码起名 transaction-manager:事务管理器id--> <tx:advice id="" transaction-manager="transactionManager"> <!--给具体的业务方法增加事务说明--> <!--属性--> <tx:attributes> <!--name:1)业务方法名 2)带有通配符的业务方法名成 3)* propagation:传播行为、isolation:隔离级别、read-only:只读、timeout:超时、rollback-for:回滚异常类列表(使用全限定名称,多个用逗号隔离)、no-rollback-for:不回滚异常类列表 --> <tx:method name="业务方法名" propagation="传播行为" isolation="隔离级别" read-only="是否只读" timeout="时间" rollback-for="回滚异常类列表"/> <tx:method name="一部分方法名结合*通配符" /> <tx:method name="*" /> …… </tx:attributes> </tx:advice> <!-- 3.声明切点表达式:表示哪些包中的那些类,类中的方法参与事务 --> <aop:config> <!--声明切点表达式 expression:切入点表达式,表示哪些包中的类中的方法参与事务--> <aop:pointcut expression="切入点表达式" id="自己起切入点表达式的名称" /> <!--关联切人点表达式和事务通知--> <aop:advisor advice-ref="事务通知id" pointcut-ref="切人点表达式id" /> </aop:config> </beans>
WEB项目
1)maven创建web项目:maven archetype webapp
2)加入 servlet 、jsp 、spring、mybatis等依赖 //别忘了web项目是war,普通Java项目是jar<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
3)创建实体类对应数据库表、Service 层、 Dao 层、
4)配置各种文件:applicationContext.xml 、jdbc.properties、mybatis.xml、pom.xml
5)创建servlet接受请求的参数,创建容器,调用Service层的Service对象
缺点:每次请求调用servlet都创建容器对象,浪费了 -----解决:该容器应该项目共享 使用监听器:
1.使用 ServletContextListener(初始时执行的方法,销毁时执行的方法)
2.创建好的容器放到ServletContext应用域中
ContextLoaderListener是一个监听器对象,是spring框架提供的,
作用:可以创建容器对象1次,把容器对象放入ServletContext应用域中
使用步骤:1.在pom.xml中加入依赖spring-web //该依赖包含了ContextLoaderListener类
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2.在web.xml声明监听器存在
3.从ServletContext中获取容器对象:String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
ServletContext sc = request对象.getServletContext //HttpServletRequest对象的方法 //获取ServletContext应用域
或:getServletContext()
sc.getAttribute(key); //获取容器对象
3.spring框架提供了一个方法可以简单地获取容器对象:WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext())
或: WebApplicationContextUtils.getWebApplicationContext(getServletContext())<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" version="5.0" metadata-complete="true"> <servlet> <servlet-name>fdsafdsagfdsafdsa</servlet-name> <servlet-class>com.bjpowernode.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>fdsafdsagfdsafdsa</servlet-name> <url-pattern>/资源/fd/saf/d/sa/fd/sa/fd</url-pattern> </servlet-mapping> <!--自定义容器使用的配置文件路径 context-param:上下文参数,给监听器提供参数的--> <context-param> <!--固定的参数名 contextConfigLocation表示自定义的spring配置文件的路径--> <param-name>contextConfigLocation</param-name> <!--自定义配置文件的路径 类路径下的xxx.xml文件--> <param-value>classpath:xxxx.xml,第二个配置文件路径,第三个,……</param-value> </context-param> <!--声明监听器 默认监听器:创建容器对象时,读取配置文件:/WEB-INF/applicationContext.xml 路径和文件名可以自定义,不适应默认规则--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
ContextLoaderListener类:
initWebApplicationContext():
创建容器对象 // WebApplicationContext时web项目中使用的容器,它继承ApplicationContext
public interface WebApplicationContext extend ApplicationContext
把容器对象放入ServletContext
6)创建jsp提交请求参数、作为视图显示请求的处理结果