1.简介
-
Spring:春天—> 给软件行业带来了春天
-
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
-
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
-
开发者Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。。。
-
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技
名词解释:
SSH : Struct2 + Spring + Hibernate! (老式)
SSM : Springmvc + Spring + Mybatis!
下载地址
Spring官方地址:Spring | Home
Spring下载地址(当然我们用不到)repo.spring.io
Spring的github地址Spring (github.com)
优点
- Spring是一个轻量级、 非侵入式的开源免费的框架 (容器) (即可以插入工程而不对原有文件运行产生干扰
- 控制反转 IoC , 面向切面 Aop (重点)
- 对事物的支持 , 对框架的支持
总结:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的框架(容器)。
spring组成
(31条消息) Spring模块组成_FYHannnnnn的博客-CSDN博客_spring组成
Spring的扩展
Spring Boot
-
一个快速开发的脚手架
-
基于SpringBoot可以快速开发单个微服务
-
约定大于配置!
Spring Cloud
- Spring CLoud是基于SpringBoot实现的
- 因为现在大所述公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用
Spring弊端:发展太久了之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱”!
Spring IOC
**Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。**在Java开发中,**Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。**如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●**谁控制谁,控制什么:**传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●**为何是反转,哪些方面反转了:**有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。**依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。**通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
使用ioc之前
使用ioc容器后:
2.第一个spring项目
1.创建一个空白的meave,删除src,然后创建子项目
2.在父项目导入配置
dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
3.创建接口和实体类
接口:
package com.ag.dao;
public interface Student {
public void learn ();
}
实现类:
package com.ag.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
public class StudentOne implements Student {
private String name;
private String grade;
@Override
public void learn() {
System.out.println(name+"在"+grade+"学习");
}
}
package com.ag.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor // 添加有参构造
public class StudentTwo implements Student {
private String name;
private String grade;
@Override
public void learn() {
System.out.println(name+"在"+grade+"学习");
}
}
4.配置Beans.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象 在Spring中这些都称为Bean
id属性:是标识单个 bean 定义的字符串。
class属性:定义 bean 的类型并使用完全限定的类名。
id属性的值是指协作对象。
property 相当于给对象中的属性设置一个值
-->
<bean id="Student01" class="com.ag.dao.StudentOne">
<!-- 无参构造是这样给成员变量赋值的,通过bean中的get方法来实现-->
<property name="name" value="张三"></property>
<property name="grade" value="一班"></property>
</bean>
<bean id="Student02" class="com.ag.dao.StudentTwo">
<!-- 有参构造是这样写的,index是第几个变量,-->
<constructor-arg index="0" value="王五"></constructor-arg>
<constructor-arg index="1" value="一班"></constructor-arg>
<!-- 当然也可以写成name-->
<!-- <constructor-arg name="grade" value="二班"></constructor-arg>-->
</bean>
</beans>
5.测试类
package com.ag;
import com.ag.dao.StudentOne;
import com.ag.dao.StudentTwo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Text {
@Test
public void Text01(){
//当运行这句话时,beans.xml里的 所有类 都已经被构造出来了,就存放在容器中!!!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
//为什么要强转呢,因为拿到的对象是object类型
StudentOne student01 = (StudentOne) context.getBean("Student01"); // 名字是id
student01.learn();
//创建对象的第二种方法,直接把实体类传过去,这样不用强转
StudentTwo student02 = context.getBean(com.ag.dao.StudentTwo.class);
student02.learn();
}
}
成功:
如果输入有特殊字符
<bean id="Student02" class="com.ag.dao.StudentTwo">
<!-- 有参构造是这样写的,index是第几个变量,-->
<constructor-arg index="0" value="王五"></constructor-arg>
<!-- 特殊字符这样处理-->
<constructor-arg index="1">
<value><![CDATA[<@@##$$⼀班>]]></value>
</constructor-arg>
<!-- 当然也可以写成name-->
<!-- <constructor-arg name="grade" value="二班"></constructor-arg>-->
</bean>
3.Spring 中的继承
Spring 继承不同于 Java 中的继承,区别:Java 中的继承是针对于类的,Spring 的继承是针对于对象(bean)。
Spring 的继承中,⼦ bean 可以继承⽗ bean 中的所有成员变量的值。
通过设置 bean 标签的 parent 属性建⽴继承关系,同时⼦ bean 可以覆盖⽗ bean 的属性值。
Spring 的继承是针对对象的,所以⼦ bean 和 ⽗ bean 并不需要属于同⼀个数据类型,只要其成员变量
列表⼀致即可。
父的值子必须有,不然报错,但是子可以有父没有的
实体类
package com.ag.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
public class StudentOne implements Student {
private String name;
private String grade;
@Override
public void learn() {
System.out.println(name+"在"+grade+"学习");
}
}
package com.ag.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
//@AllArgsConstructor // 添加有参构造
public class StudentTwo implements Student {
private String name;
private String grade;
private Integer id; // 父 没有的属性
public void learn() {
System.out.println(id);
System.out.println(name+"在"+grade+"学习");
}
}
2.配置Beans.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象 在Spring中这些都称为Bean
id属性:是标识单个 bean 定义的字符串。
class属性:定义 bean 的类型并使用完全限定的类名。
id属性的值是指协作对象。
property 相当于给对象中的属性设置一个值
-->
<bean id="Student01" class="com.ag.dao.StudentOne">
<!-- 无参构造是这样给成员变量赋值的,通过bean中的get方法来实现-->
<property name="name" value="张三"></property>
<property name="grade" value="一班"></property>
</bean>
<!-- 会继承Student01中的所有值 不要求Student02和Student01的类型一致,但是成员变量必须一致-->
<!-- 父的值子必须有,不然报错,但是子可以有父没有的-->
<bean id="Student02" class="com.ag.dao.StudentTwo" parent="Student01">
<!-- 继承父的,也可以自己写-->
<property name="grade" value="二班"></property>
</bean>
</beans>
3.测试类
public class Text {
@Test
public void Text01(){
//当运行这句话时,beans.xml里的 所有类 都已经被构造出来了,就存放在容器中!!!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
//为什么要强转呢,因为拿到的对象是object类型
StudentOne student01 = (StudentOne) context.getBean("Student01"); // 名字是id
student01.learn();
//创建对象的第二种方法,直接把实体类传过去,这样不用强转
StudentTwo student02 = context.getBean(com.ag.dao.StudentTwo.class);
student02.learn();
}
}
成功:
4.bean 的作用域
bean 是根据 scope 来⽣成,表示 bean 的作⽤域,scope 有 4 种类型:
- singleton,单例,表示通过 Spring 容器获取的对象是唯⼀的,默认值。
- prototype,原型,表示通过 Spring 容器获取的对象是不同的。
- request,请求,表示在⼀次 HTTP 请求内有效。
- session,会话,表示在⼀个⽤户会话内有效。
requset,session 适⽤于 Web 项⽬。
singleton 模式下,只要加载 IoC 容器,⽆论是否从 IoC 中取出 bean,配置⽂件中的 bean 都会被创
建。
prototype 模式下,如果不从 IoC 中取 bean,则不创建对象,取⼀次 bean,就会创建⼀个对象。
1.singleton和prototype产生对象作用域不同
设置为prototype
<bean id="Student01" class="com.ag.dao.StudentOne" scope="prototype">
<!-- 无参构造是这样给成员变量赋值的,通过bean中的get方法来实现-->
<property name="name" value="张三"></property>
<property name="grade" value="一班"></property>
</bean>
2.singleton和prototype产生对象的时间不同
这个语句执行后把所有的对象全部创建出来
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
重新编写两个实体类的无参构造函数:
public StudentOne (){
System.out.println("StudentOne");
}
public StudentTwo (){
System.out.println("StudentTwo");
}
执行:
因为默认是singleton ,只要加载 IoC 容器,⽆论是否从 IoC 中取出 bean,配置⽂件中的 bean 都会被创建。
但是如果我改成prototype
<bean id="Student01" class="com.ag.dao.StudentOne" scope="prototype">
prototype 模式下,加载IoC ,不创建对象,取的 bean时候,就会创建对象。
总结:
singleton 模式:
- 一个类用ioc创建多个对象时,返回的是同一个对象,对象唯一
- ioc容器加载,那么对象就被创建
prototype 模式:
- 一个类用ioc创建多个对象时,返回不同的对象,对象不唯一
- ioc容器加载,对象不会被创建,只有使用对象时,才会被创建
5.Spring配置说明
1.Bean的配置
<!--
id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的全限定名:包名+类名
name:也是别名,而且name可以同时取多个别名可以用空格 逗号 分号来分割
-->
<!-- alias 起别名 和name的作用一样,后来觉得太麻烦 才开发了name-->
<alias name="Student01" alias="one"></alias>
<bean id="Student01" class="com.ag.dao.StudentOne" name="s1 s2,s3;s4" scope="prototype">
<!-- 无参构造是这样给成员变量赋值的,通过bean中的get方法来实现-->
<property name="name" value="张三"></property>
<property name="grade" value="一班"></property>
</bean>
2.import导入
这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个(都在同一个resources文件目录下
假设,现在项目中有多个人开发,这三个人负责不同类的开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!使用的时候直接使用总配置就可以了。
<import resource="Spring1.xml"></import>
<import resource="Spring2.xml"></import>
6.IoC DI 依赖注入
DI 指 bean 之间的依赖注⼊,设置对象之间的级联关系。
1.实体类
package com.ag.dao;
import lombok.Data;
@Data
public class Student {
private String name;
private Integer id;
}
package com.ag.dao;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@Data
public class Teacher {
private String name;
private Student student;
private List<Student> students;
private String[] books;
private Map<String, String> card;
private Set<String> kids;
private Properties info;
}
2.beans.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student01" class="com.ag.dao.Student" >
<property name="id" value="01"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="student02" class="com.ag.dao.Student" >
<property name="id" value="02"></property>
<property name="name" value="李四"></property>
</bean>
<bean id="student03" class="com.ag.dao.Student" >
<property name="id" value="03"></property>
<property name="name" value="王五"></property>
</bean>
<bean id="teacher" class="com.ag.dao.Teacher">
<!-- 普通的写法 给属性赋值-->
<property name="name" value="李老师"></property>
<!-- ref 表示参数类型是对象,” “内是id名字-->
<property name="student" ref="student01"></property>
<!-- list 参数是对象类型-->
<property name="students">
<list>
<ref bean="student02"></ref>
<ref bean="student03"></ref>
</list>
</property>
<!-- 数组类型-->
<property name="books">
<array>
<value>《红楼梦》</value>
<value>《三国演义》</value>
<value>《西游记》</value>
<value>《水浒传》</value>
</array>
</property>
<!-- map类型-->
<property name="card">
<map>
<entry value="身份证" key="123"></entry>
<entry value="工作单位" key="吉首大学"></entry>
</map>
</property>
<!-- set类型-->
<property name="kids">
<set>
<value>son1</value>
<value>son2</value>
</set>
</property>
<!-- Properties类型-->
<property name="info">
<props>
<prop key="毕业时间">2020.1.2</prop>
<prop key="性别">男</prop>
</props>
</property>
</bean>
</beans>
3.测试类
@Test
public void Text01(){
//当运行这句话时,beans.xml里的 所有类 都已经被构造出来了,就存放在容器中!!!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println(teacher);
}
成功:
Teacher(name=李老师, student=Student(name=张三, id=1), students=[Student(name=李四, id=2), Student(name=王五, id=3)], books=[《红楼梦》, 《三国演义》, 《西游记》, 《水浒传》], card={123=身份证, 吉首大学=工作单位}, kids=[son1, son2], info={性别=男, 毕业时间=2020.1.2})
7.p,c命名空间
1.p命名空间
用来简化给属性赋值的配置,适用于实体类有无参构造
实体类:
package com.ag.dao;
import lombok.Data;
@Data
public class Student {
private String name;
private Integer id;
}
package com.ag.dao;
import lombok.Data;
@Data
public class Teacher {
private Integer id;
private String name;
private Student student;
}
配置beans.xml:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student01" class="com.ag.dao.Student" >
<property name="id" value="01"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="teacher" class="com.ag.dao.Teacher"
p:id="12" p:name="Lolita" p:student-ref="student01">
</bean>
</beans>
注意要加一条
xmlns:p="http://www.springframework.org/schema/p"
测试类:
@Test
public void Text01(){
//当运行这句话时,beans.xml里的 所有类 都已经被构造出来了,就存放在容器中!!!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println(teacher);
}
成功:
2.c命名空间
给属性赋值,适用于有参构造
实体类:
@Data
@AllArgsConstructor
public class Student {
private String name;
private Integer id;
}
beans.xml:
<bean id="student01" class="com.ag.dao.Student" c:id="01" c:name="ag">
</bean>
注意得加上:
xmlns:c="http://www.springframework.org/schema/c"
测试类:
@Test
public void Text01(){
//当运行这句话时,beans.xml里的 所有类 都已经被构造出来了,就存放在容器中!!!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//xml文件名
Student student01 = (Student) context.getBean("student01");
System.out.println(student01);
}
8.Spring的依赖
⽤来设置两个 bean 的创建顺序。
IoC 容器默认情况下是通过 beans.xml 中 bean 的配置顺序来决定创建顺序的,配置在前⾯的 bean 会
先创建。
在不更改 beans.xml 配置顺序的前提下,通过设置 bean 之间的依赖关系来调整 bean 的创建顺序。
1.实体类
@Data
public class Student {
private String name;
private Integer id;
public Student(){
System.out.println("student的无参构造");
}
}
@Data
public class Teacher {
private Integer id;
private String name;
public Teacher(){
System.out.println("teacher的无参构造");
}
}
2.beans.xml
<bean id="student" class="com.ag.dao.Student" p:name="2">
</bean>
<bean id="teacher" class="com.ag.dao.Teacher" p:name="2">
</bean>
3.测试类
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
}
构造对象的顺序是按照beans.xml 中配置顺序来决定创建顺序
修改:depends-on:依赖于。。。 在。。之后
<bean id="student" class="com.ag.dao.Student" p:name="2" depends-on="teacher">
</bean>
<bean id="teacher" class="com.ag.dao.Teacher" p:name="2">
</bean>
teacher就先创建了
9.Spring读取外部资源
实际开发中,数据库的配置⼀般会单独保存到后缀为 properties 的⽂件中,⽅便维护和修改,如果使⽤
Spring 来加载数据源,就需要在 beans.xml 中读取 properties 中的数据,这就是读取外部资源。
1.实体类
@Data
public class Mysql {
private String user;
private String password;
private String url;
private String driverName;
}
2.jdbc.properties
user = root
password = 123456
url = jdbc:mysql://localhost:3306/library
driverName = com.mysql.cj.jdbc.Driver
3.beans.xml
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="mysql" class="com.ag.dao.Mysql">
<property name="user" value="${user}"></property>
<property name="driverName" value="${driverName}"></property>
<property name="password" value="${password}"></property>
<property name="url" value="${url}"></property>
</bean>
4.测试类
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Mysql mysql = (Mysql) context.getBean("mysql");
System.out.println(mysql);
}
10.Spring工厂方法
IoC 通过工厂模式创建 bean 有两种⽅式:
- 静态工厂⽅法
- 实例工厂⽅法
区别在于静态工厂类不需要实例化,实例工厂类需要实例化
1.静态工厂方法
实体类:
@Data
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
}
静态工厂方法:
package com.ag.dao;
import java.util.HashMap;
import java.util.Map;
public class StaticStudentFactory {
private static Map<Integer,Student> studentMap;
static {
studentMap = new HashMap<>();
studentMap.put(1,new Student(1,"王五"));
studentMap.put(2,new Student(2,"李四"));
studentMap.put(3,new Student(3,"张三"));
}
public static Student getStudent(Integer id){
return studentMap.get(id);
}
}
beans.xml:
<bean id="student" class="com.ag.dao.StaticStudentFactory" factory-method="getStudent" >
<constructor-arg value="2"></constructor-arg>
</bean>
factory-method 指向静态⽅法
constructor-arg 的 value 属性是调⽤静态⽅法传⼊的参数
测试类:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
2.实例工厂方法
实例工厂:
package com.ag.dao;
import java.util.HashMap;
import java.util.Map;
public class InstanceStudentFactory {
private static Map<Integer,Student> studentMap;
public InstanceStudentFactory(){
studentMap = new HashMap<>();
studentMap.put(1,new Student(1,"王五"));
studentMap.put(2,new Student(2,"李四"));
studentMap.put(3,new Student(3,"张三"));
}
public Student getStudent(Integer id){
return studentMap.get(id);
}
}
beans.xml:
<!-- 实例⼯⼚ -->
<bean id="instanceStudentFactory" class="com.ag.dao.InstanceStudentFactory"/>
<!-- 通过实例⼯⼚获取student -->
<bean id="student2" factory-bean="instanceStudentFactory" factory-method="getStudent">
<constructor-arg value="1"></constructor-arg>
</bean>
测试类:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student2");
System.out.println(student);
}
区别:
静态⼯⼚⽅法创建 Car 对象,不需要实例化⼯⼚对象,因为静态⼯⼚的静态⽅法,不需要创建对象即可
调⽤,beans.xml 中只需要配置⼀个 bean ,即最终的结果 Car 即可。
实例⼯⼚⽅法创建 Car 对象,需要实例化⼯⼚对象,因为 getCar ⽅法是⾮静态的,就必须通过实例化
对象才能调⽤,所以就必须要创建⼯⼚对象,beans.xml 中需要配置两个 bean,⼀个是⼯⼚ bean,⼀
个是 Car bean。
beans.xml中 class + factory-method 的形式是直接调⽤类中的⼯⼚⽅法
beans.xml中 factory-bean + factory-method 的形式则是调⽤⼯⼚ bean 中的⼯⼚⽅法,就必须先创
建⼯⼚ bean。
11.Spring自动装载
⾃动装载是 Spring 提供的⼀种更加简便的⽅式来完成 DI,不需要⼿动配置 property,IoC 容器会⾃动
选择 bean 完成注⼊。
⾃动装载有两种⽅式:
- byName,通过属性名完成⾃动装载。
- byType,通过属性对应的数据类型完成⾃动装载。
1.byName
实体类:
@Data
public class Student {
private Integer id;
private String name;
}
@Data
public class Teacher {
private String name;
private Student student;
}
beans.xml:
<bean id="student" class="com.ag.dao.Student" p:name="张三" p:id="2"></bean>
<!--byName teacher的属性名(student)必须和 bean id 完全一样 -->
<bean id="teacher" class="com.ag.dao.Teacher" p:name="李老师" autowire="byName"></bean>
测试类:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Teacher teacher = context.getBean(Teacher.class);
System.out.println(teacher);
}
2.byType
beans.xml:
<bean id="student" class="com.ag.dao.Student" p:name="张三" p:id="2"></bean>
<bean id="teacher" class="com.ag.dao.Teacher" p:name="李老师" autowire="byType"></bean>
使用byType 进⾏自动装载时,必须保证 IoC 中只有⼀个符合条件的 bean,否则会抛出异常。
12.使用注解开发
Spring IoC 的作⽤是帮助开发者创建项⽬中所需要的 bean,同时完成 bean 之间的依赖注⼊关系,
DI。
实现该功能有两种⽅式:
- 基于 XML 配置。
- 基于注解。
基于注解有两步操作,缺⼀不可:
1、配置⾃动扫包。
2、添加注解。
1.常规操作
实体类:
@Data
@Component(value="st") //这个操作是给bean起名字,相当于ioc中的id
public class Student {
@Value("1") //给属性赋值
private Integer id;
private String name;
}
配置自动扫包:
<!-- 配置自动扫包-->
<context:component-scan base-package="com.ag.dao"></context:component-scan>
测试类:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student st = (Student)context.getBean("st");
System.out.println(st);
}
2.DI操作
1.实体类
@Data
@Component(value="st") //这个操作是给bean起名字,相当于ioc中的id
public class Student {
@Value("1") //给属性赋值
private Integer id;
private String name;
@Autowired
private Teacher teacher;
}
@Data
@Component
public class Teacher {
@Value("16")
private Integer age;
@Value("小卡")
private String name;
}
要把相关类加入注解,然后配上@Autowired
@Autowired默认是通过 byType 进⾏注⼊的,如果要改为 byName,需要配置 @Qualififier 注解来完成
实体类中普通的成员变量(String、包装类等)可以通过 @Value 注解进⾏赋值。
测试类:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student st = (Student)context.getBean("st");
System.out.println(st);
}
@Autowired默认是通过 byType 进⾏注⼊的,修改成 byName
@Data
@Component(value="st") //这个操作是给bean起名字,相当于ioc中的id
public class Student {
@Value("1") //给属性赋值
private Integer id;
private String name;
@Autowired
@Qualifier("tea")//修改为通过名字查找,查找名字为"tea"的bean
private Teacher teacher;
}
@Data
@Component(value = "tea")//求改ioc名字为tea
public class Teacher {
@Value("16")
private Integer age;
@Value("小卡")
private String name;
}
@Component 注解的衍生
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
这几个衍生注解在效果都是一样的,都是代表将某个类注册到Spring中,装配Bean。
当然,需要都在配置文件的context:component-scan指定范围内
- dao层 【@Repository】
- service层 【@Service】
- controller层 【@Controller】
作用域scope
通过scope注解中value来定义作用域,详解可以看bean的作用域
将该@Scope("singleton")
加在Component下面就行。
加上注解就不用再去配置文件中配置作用域了
@Data
@Component(value = "tea")//求改ioc名字为tea
@Scope("singleton")
public class Teacher {
@Value("16")
private Integer age;
@Value("小卡")
private String name;
}
小结:
xml更加万能,适用于任何场合维护简单。
注解更加方便,但是维护起来很麻烦
两者比较合理的分配:
- xml用来管理bean;
- 注解只负责完成属性的注入;
- 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的扫描支持
13.使用JavaConfig配置
JavaConfig是Spring的一个子项目。它基于Java代码和Annotation注解来描述Bean之间的依赖绑定关系。
使用JavaConfig就可以实现不需要beans配置文件,就可以将对象注册到容器中
实体类:
@Data
@Component
public class Student {
@Value("1") //给属性赋值
private Integer id;
private String name;
public Student(){
System.out.println("学生类已经加载");
}
}
@Data
@Component
public class Teacher {
@Value("16")
private Integer age;
@Value("小卡")
private String name;
public Teacher(){
System.out.println("教师类已经加载");
}
}
配置类:
//@Configuration //@Configuration将该文件标记为配置类(代替xml配置文件
//@ComponentScan("com.ag.dao") //相当于之前配置的扫包
public class configAg2 {
//@Bean
public Teacher getTeacher(){
return new Teacher();
}
}
@Configuration //@Configuration将该文件标记为配置类(代替xml配置文件
@ComponentScan("com.ag.dao") //相当于之前配置的扫包
@Import(configAg2.class)//用来联系别的配置类
public class configAg {
/* @Bean作为Spring的XML配置文件中的<bean>
这个方法的名字就相当于bean中的id属性
这个方法的返回值,就相当于bean标签中的class属性
(ps:可以使用@Bean("BeanName") 来手动指定Bean的名字)
*/
@Bean
public Student getStudent(){
return new Student();
}
}
测试类:
@Test
public void Text01(){
//AnnotationConfigApplicationContext类进行解析并注册到Bean的注册表
ApplicationContext context = new AnnotationConfigApplicationContext(configAg.class);
}
小结:
@Bean 注解默认作用域为单例singleton 作用域,可通过@Scope(”prototype“)设置为原型作用域
注意,会出现两个学生对象,一个是@bean创建的,一个是@Configuration 创建的
@bean:使用的时候,只用加@bean就行,别的注解都不用加,
@Configuration :使用的时候,必须配合@Component,@ComponentScan,这两个注解使用
14.aop
1.什么是aop
代理模式核心是AOP思想:(改人源代码相当于刨祖坟(–来自弹幕
因此当需要对源代码的业务实现进行修改时,需要面向切片编程
给源代码套个娃,即再写一个套娃的代理类,从而对源代码的业务进行修改.
AOP 实现机制 - 简书 (jianshu.com)
-
AOP(Aspect Oriented Programming):可以通过预编译方式和运行其动态代理实现在不修改源代码的情况下给程序动态统一添加某种特定功能的一种技术。
-
AOP是c(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
-
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP在Spring中的作用
提供声明式事务;允许用户自定义切面
以下名词需要了解下: (狂神的理解-)
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知 执行的 “地点”的定义。
-
连接点(JointPoint):与切入点匹配的执行点
2.aop实现方式一 :使用原生Spring API接口
1.导入aop的依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
2.接口和实现类
package com.ag.Service;
public interface userService {
public void add();
public void delete();
public void insert();
public void update();
}
package com.ag.Service;
public class userServiceImpl implements userService{
@Override
public void add() {
System.out.println("执行了增加方法");
}
@Override
public void delete() {
System.out.println("执行了删除方法");
}
@Override
public void insert() {
System.out.println("执行了插入方法");
}
@Override
public void update() {
System.out.println("执行了更新方法");
}
}
2.配置前置增强和后置增强
package com.ag.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class afterLog implements AfterReturningAdvice {
@Override //后置增强
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"执行后结果为:"+returnValue);
}
}
package com.ag.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class beforeLog implements MethodBeforeAdvice {
// method:要执行的目标对象的方法
// args:参数
// target:目标对象
@Override //前置增强
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"准备执行");
}
}
3.配置beans.xml
<!-- 注册bean-->
<bean id="user" class="com.ag.Service.userServiceImpl"></bean>
<bean id="beforeLog" class="com.ag.log.beforeLog"></bean>
<bean id="afterLog" class="com.ag.log.afterLog"></bean>
<!-- 方式一 :使用原生Spring API接口-->
<aop:config>
<!-- 切入点:expression-->
<!-- execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表)) 注意老师忽略掉修饰符了-->
<!-- (..)可以代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个参数为String类型.-->
<!-- 在这里第一个*号代表返回值不限制 第二个型号代表方法名称不限制-->
<aop:pointcut id="pointcut" expression="execution(* com.ag.Service.userServiceImpl.*(..))"/>
<!-- 环绕增强-->
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
4.测试类
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 动态代理代理的是接口
userService userService = context.getBean(userService.class);
userService.add();
}
3.aop实现方式二 :使用自定义的类
自己写的类
public class diy {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
配置
<!-- 方式2:使用自定义的方式-->
<!-- 注册类-->
<bean id="diy" class="com.ag.diy.diy"></bean>
<aop:config>
<aop:aspect ref="diy">
<!-- 切点-->
<aop:pointcut id="pointcut" expression="execution(* com.ag.Service.userServiceImpl.*(..))"/>
<!-- 通知 要执行那些方法 method=方法名-->
<aop:after method="after" pointcut-ref="pointcut" ></aop:after>
<aop:before method="before" pointcut-ref="pointcut"></aop:before>
</aop:aspect>
</aop:config>
测试
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 动态代理代理的是接口
userService userService = context.getBean(userService.class);
userService.add();
}
4.aop实现方式3 :使用注解
实体类:
package com.ag.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class diy2 {
@Before("execution(* com.ag.Service.userServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.ag.Service.userServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
// 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
@Around("execution(* com.ag.Service.userServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed(); //执行业务代码,只是标记作用
System.out.println("环绕后");
}
}
配置:
<!-- 方法3:使用注解-->
<!-- 注册-->
<bean id="diy2" class="com.ag.diy.diy2"></bean>
<!-- 开启注解支持-->
<aop:aspectj-autoproxy/>
测试:
@Test
public void Text01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 动态代理代理的是接口
userService userService = context.getBean(userService.class);
userService.add();
}
15.整合mybatis
1.环境搭建
1.导包
<dependencies>
<!-- 导入mysql依赖-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- 导入mybatis 依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- 导入junit依赖-->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<!-- 导入lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<!-- spring操作mybatis依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- spring-webmvc -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.16</version>
</dependency>
<!-- spring操作jdbc需要这个-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.16</version>
</dependency>
<!-- aspectjweaver-->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
</dependencies>
<!-- 访问非资源目录下的xml文件-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
2.连接数据库
3.在com.ag.pojo下创建一个实体类
package com.ag.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private String pwd;
}
4.在com.ag.mapper下创建接口
public interface userMapper {
public List<User> select();
}
5.写一个映射器mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.song.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from mybatis.user
</select>
</mapper>
6.配置resources下的Spring-maybatis.xml
<?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>
<package name="com.ag.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射-->
<mappers>
<mapper resource="com/ag/mapper/userMapper.xml"></mapper>
</mappers>
</configuration>
7.写一个测试类
package com.ag.test;
import com.ag.mapper.userMapper;
import com.ag.pojo.User;
import com.ag.utils.MybatisUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test {
@org.junit.Test
public void Test01() throws IOException {
// 加载配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("Spring-maybatis.xml");
//得到SqlSessionFactory
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 得到sqlsession并且开启事务提交
SqlSession sqlSession = build.openSession(true);
//得到mapper
userMapper mapper = sqlSession.getMapper(userMapper.class);
// 得到查询结果
List<User> select = mapper.select();
for (User user : select) {
System.out.println(user);
}
}
}
2.整合mybatis方法一
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory
和至少一个数据映射器类。
在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean
来创建 SqlSessionFactory
。
注意:SqlSessionFactory
需要一个 DataSource
(数据源)。这可以是任意的 DataSource
,只需要和配置其它 Spring 数据库连接一样配置它就可以了。
在resources目录下创建spring.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- DataSource:使用Spring的数据源替换Mybatis的配置 -->
<!-- 我们这里使用spring是供JDBC:org.springframework.jdbc.datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory-->
<!-- 在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean来创建 SqlSessionFactory。-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定Mybatis的配置文件-->
<property name="configLocation" value="classpath:Spring-maybatis.xml"/>
<!-- 我这里classpath不加*会报错!-->
<property name="mapperLocations" value="classpath*:com/ag/mapper/UserMapper.xml"/>
</bean>
<!-- sqlSessionTemplate就是我们平时使用的sqlSession-->
<!-- SqlSessionTemplate没有set方法只能构造器注入-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!-- 把上面得到的sqlSessionTemplate放入我们的实体类中-->
<bean id="userMapper" class="com.ag.mapper.UserMapperImpl">
<!-- 这里的name需要与实现类里的set方法的参数相同-->
<property name="sqlSessionTemplate" ref="sqlSession"></property>
</bean>
</beans>
- 然后将Mybatis的配置文件mybatis-config.xml里的代码全部删掉了(狂神建议保留别名(typeAliases)、设置(settings))
在com.ag.mapper中创建一个实现类UserMapperImpl.java 私有化sqlSessionTemplate
package com.ag.mapper;
import com.ag.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl {
//整合到类里面,到时候直接调用类的方法即可。
//我们所有的操作在原来都是用sqlSession 现在采用SQL SessionTemplate
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate){
this.sqlSessionTemplate=sqlSessionTemplate;
}
public List<User> getUser(){
userMapper mapper = sqlSessionTemplate.getMapper(userMapper.class);
return mapper.getUser();
}
}
测试类
@org.junit.Test
public void Test02(){
//其实就是将SqlSession工厂和SqlSession交给了Spring托管
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
UserMapperImpl userMapper = context.getBean(UserMapperImpl.class);
List<User> user = userMapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
}
排错
出现 org.springframework.beans.factory.BeanCreationException 异常
感谢弹幕大神:
注意如果出现报错提示sqlsessionfactory创建失败的,需要进mybatis配置文件将mapper路径删除
删除之前配置的mapper映射
<mappers>-->
<mapper resource="com/ag/mapper/userMapper.xml"></mapper
</mappers>
思路
在spring 的配置文件中:
<bean id=“dataSource” 配置数据库的基本信息 得到一个dataSource对象
<bean id=“sqlSessionFactory” 得到sqlSessionFactory 得到一个sqlSessionFactory 对象
<bean id="sqlSession"得到SqlSessionTemplate(和sqlsession一样) 得到一个SqlSessionTemplate 对象
<bean id=“userMapper” 把SqlSessionTemplate赋值给我们写的接口实现类 得到一个我们自己写的类的 对象
3.整合mybatis方法二
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看
写实现类:
// 注意,这个实现类继承SqlSessionDaoSupport 实现了我们写的userMapper的接口
public class UserMapperImpl2 extends SqlSessionDaoSupport implements userMapper {
@Override
public List<User> getUser() {
SqlSession sqlSession = getSqlSession();
userMapper mapper = sqlSession.getMapper(userMapper.class);
return mapper.getUser();
}
}
配置:
<!-- 直接把sqlSessionFactory传过去 省略了得到 sqlSessionTemplate的步骤-->
<bean id="UserMapperImpl2" class="com.ag.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
测试类:
@org.junit.Test
public void Test02(){
//其实就是将SqlSession工厂和SqlSession交给了Spring托管
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
userMapper userMapper = context.getBean(UserMapperImpl2.class);
List<User> user = userMapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
}
方法2比方法1省略了得到 <bean id="sqlSessionFactory"步骤
16.声明式事务
1.回顾事务
回顾事务
- 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
- 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
事务四个属性ACID
原子性(atomicity)
事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
一致性(consistency)
一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
隔离性(isolation)
可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
持久性(durability)
事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
2.模拟事务失败
在整合mybatis的代码上进行修改
接口:
public interface userMapper {
public List<User> getUser();
public int deleteUser(Integer id);
public int insertUser(User user);
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ag.mapper.userMapper">
<!-- 查询-->
<select id="getUser" resultType="user">
select * from mybatis.user
</select>
<!-- 删除 故意把删除方法写错-->
<delete id="deleteUser" parameterType="int">
deletes from mybatis.user where id=#{id}
</delete>
<!-- 添加-->
<insert id="insertUser" parameterType="user">
insert into user(id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
</mapper>
实现类:
/ 注意,这个实现类继承SqlSessionDaoSupport 实现了我们写的userMapper的接口
public class UserMapperImpl2 extends SqlSessionDaoSupport implements userMapper {
@Override
//查询方法 在查询前调用删除和添加方法
public List<User> getUser() {
//调用添加方法
insertUser(new User(99,"loli","123654"));
//调用删除方法
deleteUser(99);
return getSqlSession().getMapper(userMapper.class).getUser();
}
//删除方法
@Override
public int deleteUser(Integer id) {
return getSqlSession().getMapper(userMapper.class).deleteUser(id);
}
//添加方法
@Override
public int insertUser(User user) {
return getSqlSession().getMapper(userMapper.class).insertUser(user);
}
}
测试:
@org.junit.Test
public void Test02(){
//其实就是将SqlSession工厂和SqlSession交给了Spring托管
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
userMapper userMapper = context.getBean(UserMapperImpl2.class);
List<User> user = userMapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
}
代码不出意料的出错了,
当代码中有错误,尽管报错但是报错之前的数据修改仍然正常进行了,
因此我们要求开启事务,若后面报错,则之前的数据要进行回溯。
3.Spring 操作事务
两种事务管理:
-
声明式事务:AOP【一般用这个】
一般情况下比编程式事务好用。
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理 -
编程式事务:需要在代码中,进行事务的管理
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
关于Spring-dao.xml 配置文件的头部:因为后面自动生成tx(事务管理)的头部是错的,最后还得自己改
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
在Spring.xml配置事务,并且结合aop插入
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 transaction-manager:事务管理,就是我们上面配的 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 给所有方法都配置事务 -->
<!-- propagation="REQUIRED" 是默认的设 即传播特性-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 结合AOP实现事务的织入-->
<!--配置事务的切入-->
<aop:config>
<!-- com.ag.mapper包下所有文件中的所有方法 -->
<aop:pointcut id="txPointCut" expression="execution(* com.ag.mapper.*.*(..))"/>
<!-- advice-ref:插入什么东西 pointcut-ref:在哪里插入 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
执行,发现程序出错后,事务回滚,数据库没有改变