0.总结
1.mybatis
- 对jdbc的初步分装,MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
2.连接池c3p0,druid
负责数据库的连接,创建连接,释放连接。
用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
主要是管理数据库连接的
- C3P0 数据库连接池
在使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了,直接从数据源获得数据库的连接。 - Druid 相对于其他数据库连接池的优点:
3.事务处理
数据库的事务管理。保证数据库的正常运行。作用在数据源上。
1.ioc容器
- 第一步通过xml配置,交代清楚bean的类和类的id还可以配置一些初始化的参数
- 其中id是页面获取bean的主要方式。
- 创建工厂类--> 通过反射创建对象(class.newInstance)
1.ioc接口
-
ioc是个容器,本质就是一个对象的工厂。
-
spring提供了Ioc容器实现的两种接口
-
BeanFactory spring内部使用,一般不提供开发人员使用。
-
ApplicationContext:提供给开发人员使用,功能更加丰富。
区别:前者bean在调用的时候创建对象,而后者加载配置文件就自动生成bean对象。
-
2.ioc具体操作
1.bean创建
- spring帮我们创建对象
- 由Spring帮我们注入属性
2.bean管理
-
基于xml方式创建对象,
- id唯一标识符
- class对象类的全路径
- name和id差不多。
默认执行无参构造方法和get/set函数。
java在运行的时候和C++相同,如果没有任何构造函数,自动创建一个无参构造函数,如果有构造函数,不注入无参构造函数
-
基于xml注入属性
<bean id="user" class="com.demo.spring5.User"> <property name="name" value="1111"/> </bean>
-
有参数的构造:constructor-arg
- name 属性名或者index:第一个参数(0开始)
<bean id="user1" class="com.demo.spring5.User">
<constructor-arg name="name" value="1111" />
<constructor-arg index="0" value="1"/>
</bean>
-
p名称空间注入:本质无参加set
xmlns:p="http://www.springframework.org/schema/p" <bean id="user2" class="com.demo.spring5.User" p:name="22"></bean>
1.如何注入特殊值
- 空值<null/>
- 特殊符号的注入
<property name="name">
<null/>
</property>
<!--特殊符号的注入-->
<bean id="user3" class="com.demo.spring5.User">
<property name="name" >
<value><![CDATA[<<南京>>]]></value>
</property>
</bean>
2.如何注入bean
包含内部bean和级联bean
-
创建service类和Dao类,
-
通过ref实现bean的内部注入。
<!--联级bean--> <!-- bean中注入bean--> <bean id="userDao" class="com.demo.dao.UserDaoImp"/> <bean id="userService" class="com.demo.service.UserService"> <property name="userDao" ref="userDao"/> <!--也可以直接给userDao中的属性赋值,需要设置 userDao的get方法--> <property name="userDao.name"value="name"/> </bean> <!--内部bean,在property里面加入bean--> <bean id="userService" class="com.demo.service.UserService"> <property name="userDao"> <bean id="userDao" class="com.demo.dao.UserDaoImp"/> </property> </bean>
3.注入属性-内部bean和级联赋值
- 一对多关系:部门和员工
- 实体类之间表示一对多关系
3.基于xml注入集合属性
1.注入数组
2.注入list集合属和
3.注入mapper属性
<bean id="student" class="com.example.bean.Stu">
<property name="courses">
<array>
<value>java</value>
<value>sql</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<property name="map">
<map>
<entry key="Java" value="88"></entry>
<entry key="C++" value="88"></entry>
</map>
</property>
<property name="set">
<set>
<value>三好学生</value>
<value>优秀共青团员</value>
</set>
</property>
</bean>
4.注入对象数组
<!-- 给对象集合赋值-->
<property name="coursesList">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
</list>
</property>
5.抽取集合
可以通过util工具抽取集合,为了多次使用
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>九阳申通</value>
<value>易经</value>
</util:list>
<bean id="book" class="com.example.bean.Book">
<property name="list" ref="bookList"></property>
</bean>
</beans>
4.工厂bean
Spring中Bean可以分为两种,工厂bean和普通bean。
其中存在 这样的区别
- 普通bean:在配置文件定义中bean类型就是返回值类型
- 工厂bean:配置类型和返回类型可以不一样。
1.单实例和多实例
解释:正常情况下是单实例,工厂中的bean对象只有一个,不论在那个地方拿取bean使用,而多实例则是每次拿去 的bean都会重新创建,用完自动回收。
scope属性:@Scope
- prototype:多实例,懒加载
- singleton:单实例,
- request:每次创建之后会自动放到request中
- seesion:每次创建之后会自动放到seesion域中
2.自定义工厂bean
和多实例的效果相同
一般而言,在xml中注册的bean的实例接收类型只能是预设类和其子类或者是继承接口的关系,工厂bean就是注册一个工厂,获取的类型是个bean的产品。
特点:
- 继承FactoryBean<Coure>接口
- 传入产品类进行接受
public class MyBean implements FactoryBean<Course> {
@Override
public Course getObject() throws Exception {
Course coursec = new Course();
coursec.setName("abc");
return coursec;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
5.bean的生命周期
从对象的创建到对象的销毁,有哪些过程呢??
- 创建bean实例(无参构造)
- 为bean的属性注入值(set方法)
- 调用bean中初始化的方法(需要配置)
- bean可以使用了(对象的获取)
- 容器的关闭,bean的销毁
<bean id="book" class="com.example.bean.Book" init-method="Init" destroy-method="destory">
<property name="list" ref="bookList"></property>
</bean>
此外还可以有多余的两步,在初始化的前后设置前置和后置处理器。
bean的前后置处理器
指的是在初始化前后加入前后置处理器。BeanPostProcessor
bean实际可以扩充成七步。
- 设置前后置处理器
- 配置前后置处理器
- 可以直接在xml中将后置处理器注册成bean,这个可以处理器对所有的bean有效
public class MyBeanPost implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
<bean id="myBeanProcess" class="com.example.bean.MyBeanPost"/>
6.自动注入
自动注入有两张方法: byName,byTye,反别是更具bean的id和class去注入属性。
<bean id="book" class="xxxx" autowire="byName"/>
<bean id="book" class="xxxx" autowire="byType"/>
其中byName,就是看bean的id注入
- 开启自动注入
总结:其实自动装配可以看成是初步注入完bean之后,二次注入bean.写配置的时候无先后之分。属于bean的管理
3.bean管理
1.属性值分离
1引入外部配置文件context:property-placeholder,需要先添加命名空间
2.${}取属性的值,
<xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
4.注解
为了简化xml的配置.
1.创建对象
- @Component
- @Service
- @Controller
- @Repositry
功能是一致的,只是为了方便开发.
步骤:
- 引入依赖
- 开启组件扫描,多个用逗号隔开
- 在很多属性是数组,如果在xml配置中,使用,分割在注解中使用{}加,分割
<context:component-scan base-package="com.example.bean,com.example.bean.Course"/>
包扫描写法
- 多个包用逗号隔开
- use-default-filters设置为false,可以自己设置扫描条件.,这里的扫描条件是根据注解的类型进行扫描
- 关闭默认的过滤器,开启自己定义要扫描的类
- 使用默认的过滤器,关闭相应的扫描类
- 排除的内容可以用默认扫描加上排除的内容
<context:component-scan base-package="com.autowire.bean" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
1.属性分析
- value ~~id不写默认是类名
2.注入属性
1.bean注入
@Autowired
bean的注入,根据类型自动注入。
不需要添加set方法帮我们封装了
@Qualifier
根据名称注入,需要个@Autowire的联合使用,存在多个相同类型的bean的时候,很适合根据名称注入
@Resource
单独使用,本身是javax里面的
- @Resource
- @Resource(name="userDao1")
混合方式注入。
@Service(value="userService")
public class UserService {
@Autowired
@Qualifier(value = "userDao1")
private UserDao userDao;
public void add(){
userDao.add();
System.out.println("service add..");
}
}
2.普通属性注入@Value
3.纯注解开发@Configuration
需要完全替代配置文件,所以要创建配置类Config,开启包扫描.
@Configuration
@ComponentScan(basePackages = {"com.autowire"})
public class FullyDemo1 {
}
public class FullyAuto1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FullyDemo1.class);
UserService service = context.getBean("userService", UserService.class);
service.add();
}
}
2AOP
- 面向切面编程,就是对方法进行增强,降低业务逻辑之间的耦合度。
核心就是在不修改原始代码的方式添加新功能。
0.类加载器
类加载器的作用是,将class文件读入,定义成一个class类。然后就可以通过newInstance获取到实例。它的基本的功能和xml配置类的读取类似。
一个类要相同,则需要他们的全类名和类加载器完全相同。
1.自定义类加载器
//该加载器可以加载与自己在同一路径下的Class文件
public class MyClassLoader extends ClassLoader{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException{
try {
String fileName=name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is=getClass().getResourceAsStream(fileName);
if(is==null){
//不在当前路径下的类,例如Object类(JavaBean的父类),采用委派模型加载
return super.loadClass(name);
}else{
//在当前路径下的类,例如JavaBean类,直接通过自己加载其Class文件
byte[] b=new byte[is.available()];
is.read(b);
return defineClass(name,b,0,b.length);
}
} catch (IOException e) {
throw new ClassNotFoundException();
}
}
}
1.概念与原理
过程:
- 配置切面类(增强方法集合)
- 配置切入点
- aop植入
1.底层原理
- Aop使用的是动态代理的方式。
第一种 有接口的情况,使用JDK动态代理。
创建代理对象,代理能使用原本对象的所有方法,同时可以进行增强,接口实现类代理对象。
第二种 无接口的情况 , 使用CGLIB动态代理。
代理对象实际是重写个子类的代理对象
2.jdk动态代理
做法就是通过Proxy.newProxyInstance()方法创建代理对象。
第一个参数,jdk动态代理器的类加载器,就是当前类的加载器。
第二个参数,接口数组,用来规定代理的方法
第三个参数 ,实际代理对象,用来写增强方法
public class Typical {
public static void main(String[] args) {
// 代理方法的接口
Class[] interfaces={UserDao.class};
UserDao userDao = new UserDaoImp();
UserDao instance = (UserDao) Proxy.newProxyInstance(Typical.class.getClassLoader(), interfaces, new UserProxy(userDao));//用代理对象类生成代理对象,
instance.add(1,2);
}
}
class UserProxy implements InvocationHandler {//增强方法,参数是被代理的对象
private Object object;
UserProxy(Object userDao){
object = userDao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法前..");
Object invoke = method.invoke(object, args);
System.out.println(invoke);
System.out.println("执行方法后..");
return invoke;
}
}
2.术语
-
连接点: 被增强的方法。
-
切入点:实际被增强的方法
-
通知
- 增强的逻辑
- 通知类型
- 前置通知,在方法前
- 后置通知,在方法后
- 环绕通知,
- 异常通知,发生异常时的处理
- 最终通知,所有结束的通知
-
切面
是个动作,就是把通知应用到切点的过程。
AspectJ
spring框架是基于Aspectj实现的AOP操作,它是个独立的AOP框架,只是联合起来一起使用。
基于AspecJ实现AOP:
- 配置文件
- 基于注解实现
所需依赖:
切入点表达式
- 语法结构
execution([权限修饰符][返回类型][类全路劲][方法名称][参数列表]);
返回类型可以不写;
execution(*com.example.bean.User.*(..))
基于注解的AspectJ
1.用注解生成bean
被代理对象和代理对象都需要先生成ben
2.配置开始代理模式Aop
开启动态代理,部分的功能是使得一些注解和标签可以被spring框架识别。
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.写代理类(增强方法的集合)
- 公共的切入点可以通过方法抽取。Pointcut()
@Before(value="com.AspectJ.proxy.UserProxy.pointCut()")同时切入点也可以写成一个专门的类,通过全类名调用。
package com.AspectJ.proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Author coder
* @Date 2021/10/21 13:29
* @Description
*/
@Component
@Aspect
public class UserProxy {
//连接点可以通过方法抽取
@Pointcut(value="execution(* com.AspectJ.bean.User.*(..))")
public void pointCut(){
}
@Before(value="pointCut()")
public void before(){
System.out.println("before...");
}
@Before(value="execution(* com.AspectJ.bean.User.*(..))")
public void before(){
System.out.println("before...");
}
@After(value="execution(* com.AspectJ.bean.User.*(..))")
public void finaRes(){
System.out.println("after...");
}
@AfterReturning(value="execution(* com.AspectJ.bean.User.*(..))")
public void after(){
System.out.println("afterReturning..");
}
@AfterThrowing(value="execution(* com.AspectJ.bean.User.*(..))")
public void ocuurEror(){
System.out.println("error occured..");
}
@Around(value="execution(* com.AspectJ.bean.User.*(..))")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前..");
point.proceed();
System.out.println("环绕后..");
}
}
代理的方法分为5类,前置,后置,环绕,异常方法,最终方法。执行顺序:
环绕前..public void around(ProceedingJoinPoint point)
before
方法
环绕后
后置
最终
一场方法会中断这一过程,其他过程可掠过,但最终过程不会省略.
-
@Order当有多个方法对内容进行中增强的时候,可以设立增强类的优先级,
相对于对一个方法进行增强之后的方法进一步增强,优先级越高,增强方法包裹在越外面.@Order(1)数值越小,优先级越高。
基于xml的代理配置
<bean id="book" class="com.AspectJ.aopxml.Book"/>
<bean id="proxy1" class="com.AspectJ.aopxml.ComProxy1"/>
<aop:config>
<!-- 配置公共的切点-->
<aop:pointcut id="point1" expression="execution(* com.AspectJ.aopxml.Book.*(..)"/>
<!-- 配置切面类,切面由增强方法和切点组成,需要先指定是那个增强类,切面就是增强方法的集合-->
<aop:aspect ref="proxy1">
<aop:before method="before" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
基于全注解配置
就是需要用注解开启包扫描和AOP代理
- 开启某一项功能的注解:@EnableAspectJAutoProxy(proxyTargetClass=true)
3.JDBC
1.所需的依赖
- spring-jdbc
- spring-orm(整合其他的框架用的)
- spring-tx事务管理
- mysql-connector-java
- druid-1.1.9.jar连接池
2注册druid连接池
3.注册jbcTemplate模板
4.配置到dao,service
批量处理
- BatchQuery(sql,list); list是传递的参数值构成对象的集合。
传递Object[]数组的集合.
4.事务的概念
1.事务的基本知识
1. 事务是数据库操作的基本单元,逻辑上一组操作,要么成功,要么都失败。方法对数据库的操作具有一致性,原子性,隔离性,持久性。
2. 事务的特性**ACID**
1. 原子性
2. 一致性,有增有减
3. 隔离性, 事务之间不会相互影响
4. 持久性,数据库修改之后持久的变化。
事务就是有些事要么一起做,要么都不做,做到一半出现异常需要进行回滚。
开启事务的方法:
-
开启事务
-
进行业务逻辑
-
没有异常提交
-
有异常进行回滚
事务一般加载service层,Spring事务管理有两种
- 编程式事务管理
- 声明式事务管理
- 基于注解
- 基于xml配置文件
- 底层是AOP操作。
2.事务管理器操作
1.配置事务管理器(基于注解)
-
配置事务管理器下,需要告诉使用的是哪个数据库连接池
-
开始事务管理,需要注入数据源
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/>
-
对需要增强的方法(或者类)添加注解
2.事务注解中的常用参数
-
propagation: 传播行为
事务方法:使得表中的数据发生变化的操作,就是事务方案。
是多事务方法之间的调用。有事务的方法调用没有事务的方法,没有事务的方法调用有事务的方法....
事务传播有七种行为:
- required: add里面有事务,调用其他方法会自动使用当前的事务。如果add没事务,则创建一个新的事务。
- required_new: add调用update,不论add是否有事务,都会自己创建一个新事务,将原来的挂起。
- PROPAGATION_REQUIRED
Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行 - PROPAGATION_REQUES_NEW
该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可 - PROPAGATION_SUPPORT
如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务 - PROPAGATION_NOT_SUPPORT
该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码 - PROPAGATION_NEVER
该传播机制不支持外层事务,即如果外层有事务就抛出异常 - PROPAGATION_MANDATORY
与NEVER相反,如果外层没有事务,则抛出异常 - PROPAGATION_NESTED
该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
-
isolation: 事务的隔离级别
正在使用的数据会被隔离
多事务操作之间不会产生影响,我们称为事务的隔离性。不隔离会产生诸多的问题:脏读(一个事务读取到另一个正在运行的事务的数据),不可重复读(一个未提交的事务读取到另一个提交事务修改的数据,未提交的事务每次读出的数据不一样),幻读(一个为提交的事务读到了另一个事务新增的记录);
利用事务的隔离性,来解决这些问题。
- read uncommited(读未提交的)
- read commited(读已提交的数据)
- repeated read默认为可重复读
-
timeout:超时时间
事务在规定时间内提交。否则回滚,默认为-1,不操作。
-
readOnly: 是否只读
默认值为false,只可以查询到意思。
-
rollbackFor()回滚
设置出现哪些异常进行回滚
-
norollbackFor()
出现哪些异常不进行回滚。
3.基于xml配置事务
- 在spring中配置事务管理器
- 配置通知(增强的部分)tx-advice,如果是切面的话配置代理类和切面方法,事务则是配置通知。
- 配置切点和切面。
开始事务不需要了,因为不需要进行事务扫描,自己配置。
4.完全注解开发
- 将事务bean取代,通过@Bean实现,
- @Bean指定的方法所需的参数默认自动通过已有的bean注入,核心根据类型注入.
- 通过注解开启事务扫描。@EnableTransactionManagement